# jonfk/calc

A toy language for calculating simple expressions
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
 Failed to load latest commit information. ast lex parse test_input .travis.yml README.md main.go

# calc

My toy calculator language. The lexer was inspired by the text/template/parse package from the standard library and this talk by Rob Pike: Lexical Scanning in Go The parser is a custom recursive descent parser. The parsing support was also inspired by go/parser and text/template/parse.

###TODO

• Add more tests for parser
• Test error cases for parser and lexer
• Add better error messages to parser
• Add support for val declarations
• Add support for var declarations
• Add eval package and implement an interpreter
• Add support for let statements
• Add "=>" token to lexer
• keep parsing expression if in a paren
• Add support for function literals
• Add support for function declarations
• Add references and probably some for of gc
• Add doc comment support to parsing
• Add typing system(?) or go with dynamic typing
• Vendor dependencies(or remove them)

###Notes

• Identifiers can be alphanumeric with an underscore '_'
• Expressions can end with a ';' but ';' are not strictly necessary. They can be used to disambiguate certain expressions.
• Unary Expressions cannot span multiple lines
• Binary Expressions can span multiple lines only if line ends with operator
• Parenthesis allows expressions to span multiple lines until the parenthesis is closed
• Operator precedence are left binding and as follows:
``````Highest(5): *, /, %
(4): +, -
(3): ==, !=, <, >, <=, >=
(2): &&
Lower  (1): ||
Lowest (0): anything else

e.g 4+2/3 == 4 + (2/3)
4-5+4%a+5 == ((4 - 5) + (4%a)) + 5
``````

##Grammar in EBNF

``````literal = NUMBER
| IDENTIFIER
| BOOL

if_expr = "if" , bool_expr , "then" , expr , "else" , expr "end"

num_expr = "+" , expr
| "-" , expr
| expr , "+" , expr
| expr , "-" , expr
| expr , "*" , expr
| expr , "/" , expr
| expr , "%" , expr

bool_expr = "!" , expr
| expr , "&&" , expr
| expr , "||" , expr
| expr , "==" , expr
| expr , ">" , expr
| expr , "<" , expr
| expr , "!=" , expr
| expr , ">=" , expr
| expr , "<=" , expr

tuple_expr = "(" , expr , "," , expr , { "," , expr } , ")" # n > 1

function = "fn" , "(" , ident_stmt , ")" , "=>" , expr , "end" # remove end keyword ?

block = expr , { ("\n" | ";") , expr}

let_expr = "let" , val_decl , "in" , expr , "end"

expr = literal
| num_expr
| bool_expr
| if_expr
| "(" , expr , ")"
| tuple_expr
| let_expr
| block
| function
| func_apcl

func_apcl = (IDENTIFIER | function ) , "(" , expr , { "," , expr } , ")"

ident_stmt = IDENTIFIER

decl = val_decl
| var_decl

val_decl = "val" , ident_stmt , "=" , expr

var_decl = "var" , ident_stmt , "=" , expr

func_decl = "def" , IDENTIFIER , "(" , IDENTIFIER , { "," , IDENTIFIER } , ")" , "=" , expr , "end"
``````

###Planned Extensions to grammar

• Add pattern matching to grammar
``````pattern = "(" , pat , "," , pat , { "," , pat } , ")" # n > 1
| literal

val_decl = "val" , pat , "=" , expr
``````

##Dependencies Depedencies are kept to a minimum.

```# Used for testing and debugging
go get github.com/davecgh/go-spew/spew```