X-Git-Url: https://code.consxy.com/gitweb/gitweb.cgi?a=blobdiff_plain;f=src%2Fmain%2Fparse.lisp;h=10e2f08aa25575207dab84d1433eae82e919188a;hb=c34fdd7;hp=40be292d3d97fe2ab18955627409aaac2cfe35d8;hpb=c5613b87ab91b845b628d9201ad053da92912838;p=clnl diff --git a/src/main/parse.lisp b/src/main/parse.lisp index 40be292..10e2f08 100644 --- a/src/main/parse.lisp +++ b/src/main/parse.lisp @@ -1,4 +1,4 @@ -(in-package #:cl-nl.parser) +(in-package #:clnl-parser) ; Ok, after thinking about this a little, the parser is completely contextual ; based on what has come before. We can't do a contextless parsing, like we @@ -24,21 +24,17 @@ (defun prim-name (prim) (getf prim :name)) (defun prim-num-args (prim) (length (getf prim :args))) +(defun prim-args (prim) (getf prim :args)) (defun find-prim (symb) (find symb *prims* :key #'prim-name)) -; We don't care if it's a command! -;(defun is-command (symb) -; (let -; ((prim (find-prim symb))) -; (and prim (eql :command (getf prim :type))))) - ; Make this only as complicated as it needs to be, letting it grow ; as we take on more and more of the language (defun parse (lexed-ast) (cond ((not lexed-ast) nil) ((numberp (car lexed-ast)) (cons (coerce (car lexed-ast) 'double-float) (parse (cdr lexed-ast)))) + ((eql :[ (car lexed-ast)) (parse-block (cdr lexed-ast))) ((and (symbolp (car lexed-ast)) (find-prim (car lexed-ast))) (let* ((prim (find-prim (car lexed-ast))) @@ -47,10 +43,38 @@ (cons (cons (prim-name prim) - (butlast parsed-remainder (- (length parsed-remainder) num-args))) + (mapcar + #'help-arg + (prim-args prim) + (butlast parsed-remainder (- (length parsed-remainder) num-args)))) (nthcdr num-args parsed-remainder)))) (t (error "Couldn't parse ~S" lexed-ast)))) +(defun help-arg (arg-type arg) + (case arg-type + (:command-block + (if (not (and (consp arg) (eql 'block (car arg)))) + (error "Required a block, but found a ~A" arg) + (cons :command-block (cdr arg)))) + (t arg))) + +(defun parse-block (tokens) + (multiple-value-bind (in-block after-block) (find-closing-bracket tokens) + (cons + (cons + 'block + (parse in-block)) + (parse after-block)))) + +(defun find-closing-bracket (tokens &optional (depth 0)) + (cond + ((not tokens) (error "Failed to find a matching closing bracket")) + ((and (eql :] (car tokens)) (= depth 0)) (values nil (cdr tokens))) + (t (multiple-value-bind + (in-block after-block) + (find-closing-bracket (cdr tokens) (case (car tokens) (:[ (1+ depth)) (:] (1- depth)) (t depth))) + (values (cons (car tokens) in-block) after-block))))) + (defmacro defprim (name args) `(push (list :name ,name :args ',args) @@ -59,6 +83,12 @@ ; This list of prims will get combined with the mapping to actual code later ; Current list of argument types we accept: ; - :number +; - :agentset +; - :command-block ; - t - any type +(defprim :ask (:agentset :command-block)) (defprim :crt (:number)) +(defprim :fd (:number)) +(defprim :random-float (:number)) (defprim :show (t)) +(defprim :turtles ())