diff options
| author | Jakob L. Kreuze | 2023-05-12 13:15:07 -0400 |
|---|---|---|
| committer | Jakob L. Kreuze | 2023-05-12 13:15:07 -0400 |
| commit | 79b39cb5bb6203f3a1ced5d3e2d61f08d7abe3eb (patch) | |
| tree | 94a7b0490c3ba2ac36af754ce5cca005b7a4a7b1 | |
| parent | 1ab7d7a0c7cc40ab37b2f3285252dc0b062915c2 (diff) | |
Some processing order issues resolved
| -rw-r--r-- | compiler/passes/emit-specification.scm | 4 | ||||
| -rw-r--r-- | compiler/passes/parse-policy.scm | 152 |
2 files changed, 68 insertions, 88 deletions
diff --git a/compiler/passes/emit-specification.scm b/compiler/passes/emit-specification.scm index 37d0aa8..7aae195 100644 --- a/compiler/passes/emit-specification.scm +++ b/compiler/passes/emit-specification.scm @@ -68,11 +68,11 @@ (define (compile-rule-group group) (match group ((left rules ...) - (assert (is-a? left <reference>)) + (assert (is-a? left <variable-ref>)) (make <lean-predicate> ;; TODO: Not really correct now, is it? #:kind (kind (head (first rules))) - #:name (reference->string left) + #:name (inner left) ;; TODO: Find unique name #:subject "v" #:default (if (find-default rules) diff --git a/compiler/passes/parse-policy.scm b/compiler/passes/parse-policy.scm index b4e2075..840460b 100644 --- a/compiler/passes/parse-policy.scm +++ b/compiler/passes/parse-policy.scm @@ -24,8 +24,17 @@ #:use-module (srfi srfi-1) #:use-module (srfi srfi-2) #:use-module (srfi srfi-26) + #:use-module (ice-9 pretty-print) ;; Temporary #:export (parse-policy)) +(define (parse-policy ast) + "Parse `ast', an abstract syntax tree from OPA, into a `<policy>'" + (assert (list? ast)) + (make <policy> + #:package (extract-package ast) + #:imports (extract-imports ast) + #:rules (extract-rules ast))) + (define (extract-package ast) "Return, as a string, the name of the package specified by `ast'" (define package-spec (assoc-ref ast "package")) @@ -65,20 +74,40 @@ ".")) values))) -(define (preprocess-rules ast) - (define rules (array->list (assoc-ref ast "rules"))) +(define (extract-rules ast) + "Group rules in `ast' by name, parsing each into a <rule> record" (define (recur rule) - (if (assoc-ref rule "else") - (list (assoc-ref rule "default") - (preprocess-head (assoc-ref rule "head")) - (make <body> - #:conjunction (preprocess-body (assoc-ref rule "body"))) - (recur (assoc-ref rule "else"))) - (list (assoc-ref rule "default") - (preprocess-head (assoc-ref rule "head")) - (make <body> - #:conjunction (preprocess-body (assoc-ref rule "body")))))) - (map recur rules)) + (make <rule> + #:default (assoc-ref rule "default") + #:head (preprocess-head (assoc-ref rule "head")) + #:body (make <body> + #:conjunction (extract-conjunction (preprocess-body (assoc-ref rule "body")))) + #:else-arm (if (assoc-ref rule "else") + (recur (assoc-ref rule "else")) + #f))) + (define rules + (let ((rules (array->list (assoc-ref ast "rules")))) + (map recur rules))) + (define targets + (map (match-lambda + (($ <rule> _default head _body _else) + (left head))) + rules)) + (define result + (map (lambda (target) + (cons target + (filter (match-lambda + (($ <rule> _default head _body _else) + (equal? target (left head)))) + rules))) + targets)) + (delete-duplicates! targets) + + ;; No individual rule should have failed to extract. + (assert (every identity result)) + + (pretty-print (to-pretty-sexp result)) + result) (define (determine-head-kind head-obj) "Return the appropriate symbol describing the kind of rule that `head-obj' represents @@ -97,15 +126,18 @@ field-eqv: assignment to a reference (varname[field] IS value IF condition) (define (preprocess-head head-obj) ;; Head rules will sometimes have an "assign" key, but this is only when the ;; right-hand side is a scalar value. + (define lhs (preprocess-body (array->list (assoc-ref head-obj "ref")))) + (define rhs (preprocess-body + (if (eqv? 'set-memq (determine-head-kind head-obj)) + (assoc-ref head-obj "key") + (assoc-ref head-obj "value")))) + (assert (= 1 (length lhs))) (let ((kind (determine-head-kind head-obj))) (make <head> #:name (assoc-ref head-obj "name") #:kind kind - #:lhs (parse-reference (assoc-ref head-obj "ref")) - #:rhs (parse-literal - (if (eqv? kind 'set-memq) - (assoc-ref head-obj "key") - (assoc-ref head-obj "value")))))) + #:lhs (first lhs) + #:rhs rhs))) (define (preprocess-body body-obj) (cond ;; Non-array strings should be turned into lists. @@ -131,24 +163,14 @@ field-eqv: assignment to a reference (varname[field] IS value IF condition) "Parse into a Scheme record `term-obj' containing `type,' `value' keys" (match (assoc-ref term-obj "type") ("var" (parse-variable-ref term-obj)) - ("ref" (make <reference> #:parts (assoc-ref term-obj "value"))) + ("ref" (parse-reference (assoc-ref term-obj "value"))) ("call" (let ((parts (assoc-ref term-obj "value"))) (make <funcall> #:name (first parts) #:args (drop parts 1)))) (_ (parse-constant term-obj)))) (define (pairs->object-literal pairs) - (let* ((pairs (array->list pairs)) - (pairs (map array->list pairs))) - (make <object-literal> - #:pairs - (map (lambda (pair) - ;; Assumption that the object is represented as pairs of constant - ;; objects where the first is the key name and the second is the - ;; value. - (assert (string= "string" (assoc-ref (first pair) "type"))) - (let ((key (assoc-ref (first pair) "value"))) - (cons key (parse-literal (second pair))))) - pairs)))) + (make <object-literal> + #:pairs pairs)) (define (parse-constant term-obj) "Parse a constant literal (boolean, number, string, array, set, or object)" @@ -168,86 +190,48 @@ field-eqv: assignment to a reference (varname[field] IS value IF condition) ((string= "arraycomprehension" type) (make <comprehension> #:kind 'array - #:key (parse-variable-ref (assoc-ref value "term")) + #:key (parse-literal (assoc-ref value "term")) #:value #f - #:body (preprocess-body (assoc-ref value "body")))) + #:body (extract-conjunction (preprocess-body (assoc-ref value "body"))))) ((string= "setcomprehension" type) (make <comprehension> #:kind 'set - #:key (parse-variable-ref (assoc-ref value "term")) + #:key (parse-literal (assoc-ref value "term")) #:value #f - #:body (preprocess-body (assoc-ref value "body")))) + #:body (extract-conjunction (preprocess-body (assoc-ref value "body"))))) ((string= "objectcomprehension" type) (make <comprehension> #:kind 'object - #:key (parse-variable-ref (assoc-ref value "key")) - #:value (parse-variable-ref (assoc-ref value "value")) - #:body (preprocess-body (assoc-ref value "body")))) - ;; (else (error "unidentified type" type)) - (else value) - )))) + #:key (parse-literal (assoc-ref value "key")) + #:value (parse-literal (assoc-ref value "value")) + #:body (extract-conjunction (preprocess-body (assoc-ref value "body"))))) + (else (error "unidentified type" type)))))) (define (parse-variable-ref term-obj) "Parse a reference to a named variable" (make <variable-ref> #:name (assoc-ref term-obj "value"))) (define (parse-reference ref-obj) - (assert (array? ref-obj)) - (make <reference> #:parts (map parse-literal (array->list ref-obj)))) + (assert (list? ref-obj)) + (make <reference> #:parts ref-obj)) -(define (preprocess-policy ast) - "Lift metadata and pre-process rules of `ast' to be more easily worked with in `parse-policy'" - (assert (list? ast)) - (make <policy> - #:package (extract-package ast) - #:imports (extract-imports ast) - #:rules (preprocess-rules ast))) - -(define (extract-rules rules) - "Group rules in `ast' by name, parsing each into a <rule> record" - (define targets (map (lambda (rule) (left (second rule))) rules)) - (define result - (map (lambda (target) - (cons target - (map (lambda (x) (apply extract-rule x)) - (filter (lambda (rule) - (equal? target (left (second rule)))) - rules)))) - (delete-duplicates! targets))) + - ;; No individual rule should have failed to extract. - (assert (every identity result)) - result) (define* (extract-rule default head body #:optional else-arm) "Extract an individual parsed rule" (if else-arm (make <rule> #:default default - #:head (extract-head head) + #:head head #:body (make <body> #:conjunction (extract-conjunction (inner body))) #:else-arm (apply extract-rule else-arm)) (make <rule> #:default default - #:head (extract-head head) + #:head head #:body (make <body> #:conjunction (extract-conjunction (inner body)))))) -(define (extract-head head) - "Process any nested conjunctions in HEAD" - ;; Every part of the conjunction is an alist with a `terms' field. - (match head - (($ <head> _name _kind _lhs - ($ <constant> ($ <comprehension> kind key value body))) - (with-modified-slot head 'rhs - (make <constant> - #:value (make <comprehension> - #:kind kind - #:key key - #:value value - #:body (extract-conjunction body))))) - (_ head))) - (define (extract-conjunction conjunction) "Extract the body of a parsed rule" ;; Every part of the conjunction is an alist with a `terms' field. @@ -270,7 +254,3 @@ field-eqv: assignment to a reference (varname[field] IS value IF condition) (if (and (alist? term-obj) (assoc "symbols" term-obj)) (make <exists-some> #:identifiers (assoc-ref term-obj "symbols")) term-obj)) - -(define (parse-policy ast) - "Parse `ast', an abstract syntax tree from OPA, into a `<policy>'" - (over (ι-policy-rules) extract-rules (preprocess-policy ast))) |