First ugly pass of show
[clnl] / src / main / parse.lisp
1 (in-package #:cl-nl.parser)
2
3 ; Ok, after thinking about this a little, the parser is completely contextual
4 ; based on what has come before.  We can't do a contextless parsing, like we
5 ; could in other languages, due to amiguity about reporters vs reporter tasks
6 ;
7 ; So, for instance, we could have:
8 ;   x + y => (+ x y)
9 ;   x + y => (x (task +) y)
10 ; So the definition of "+" is completely dependent on the nature of x
11 ;
12 ; The goal of this parser should be to turn in the amiguous lexed ast representing
13 ; NetLogo into an unambigious S-expression, and nothing more, so things like
14 ; expectation of commands being the first symbol is not be necessary until later
15 ;
16 ; In general, the parser will:
17 ;  * Parse the structure of the lexed output first
18 ;  * Parse the structure of the individual expressions (finding ('s and ['s and doing the right thing)
19 ;  * Coalate things into an unambigious expressions
20 ;  * Then we're done, let someone else make it evaluatable
21 ;    - We don't really care if things are commands or reporters right now
22
23 (defparameter *prims* nil)
24
25 (defun prim-name (prim) (getf prim :name))
26 (defun prim-num-args (prim) (length (getf prim :args)))
27
28 (defun find-prim (symb) (find symb *prims* :key #'prim-name))
29
30 ; We don't care if it's a command!
31 ;(defun is-command (symb)
32 ; (let
33 ;  ((prim (find-prim symb)))
34 ; (and prim (eql :command (getf prim :type)))))
35   
36 ; Make this only as complicated as it needs to be, letting it grow
37 ; as we take on more and more of the language
38 (defun parse (lexed-ast)
39  (cond
40   ((not lexed-ast) nil)
41   ((numberp (car lexed-ast)) (cons (coerce (car lexed-ast) 'double-float) (parse (cdr lexed-ast))))
42   ((and (symbolp (car lexed-ast)) (find-prim (car lexed-ast)))
43    (let*
44     ((prim (find-prim (car lexed-ast)))
45      (num-args (prim-num-args prim))
46      (parsed-remainder (parse (cdr lexed-ast))))
47     (cons
48      (cons
49       (prim-name prim)
50       (butlast parsed-remainder (- (length parsed-remainder) num-args)))
51      (nthcdr num-args parsed-remainder))))
52   (t (error "Couldn't parse ~S" lexed-ast))))
53
54 (defmacro defprim (name args)
55  `(push
56    (list :name ,name :args ',args)
57    *prims*))
58
59 ; This list of prims will get combined with the mapping to actual code later
60 ; Current list of argument types we accept:
61 ; - :number
62 ; - t - any type
63 (defprim :crt (:number))
64 (defprim :show (t))