Grotsky Part 1: Syntax
Syntax Restrictions
Primitives
Example of functions and operations
## Arithmethic print(2^10 - 2323*3) # Output: -5945 print(2^(12*3+400/-4+10*5/2)) # Output: 1.8189894035458565e-12 ## Logic print(true or false) # Output: true (short circuit) print(false and true) # Output: false (short circuit) ## Conditionals if 3 > 2 or (1 < 3 and 2 == 2) begin print('Condition is true') end elif 3 == 4 begin print('Condition 2 is true') end else begin print('Conditions are false') end ## Lists for i in [1, 2, 3, 4] begin print(i) end let lst = [1, 2, 3, 4] lst[0] = -1 print(lst) # Output: [-1, 2, 3, 4] print(lst[1:3]) # Output: [2, 3] ## Dictionaries # (dictionaries and lists not allowed as keys) let dct = { "Key1": "Val1", 2: "Val2", true: false } for key, val in dct begin print(key, val) end ## Functions fn square(x) begin return x^2 end fn operate(x, operation) begin return operation(x) end ## Clojure fn makeCounter() begin let n = 0 return fn() begin n = n+1 return n end end ## Classes class Counter begin init(start) begin self.start = start end count() begin self.start = self.start+1 return self.start end end class CounterTwo begin count() begin return super.count()*2 end end
Syntax definition
Let's build a syntax definition in backus naur format that will be easy to parse with a recursive descent parser.
Expresions
expression assignment; list "[" arguments? "]"; dictionary "{" dict_elements? "}"; dict_elements keyval ("," keyval)*; keyval expression ":" expression; assignment (call ".")? IDENTIFIER "=" assignment | access; access logic_or ("[" slice "]")*; logic_or logic_and ("or" logic_and)*; logic_and equality ("and" equality)*; equality comparison (("!=" | "==") comparison)*; comparison addition ((">" | ">=" | "<" | "<=") addition)*; addition multiplication (("-" | "+") multiplication)*; multiplication power (("/" | "*") power)*; power unary ("^" unary)*; unary ("not" | "-") unary | call; call primary ("(" arguments? ")" | "." IDENTIFIER)*; arguments expression ("," expression)*; slice (":" expression) | (":" expression ":" expression) | (":" ":" expression) | expression | (expression ":") | (expression ":" expression) | (expression ":" ":" expression) | (expression ":" expression ":" expression); primary NUMBER | STRING | "false" | "true" | "nil" | IDENTIFIER | "(" expression ")" | fnAnon | list | dictionary; fnAnon "fn" "(" parameters? ")" block;
Statements
program declaration* EOF; declaration classDecl | funDecl | varDecl | statement; classDecl "class" IDENTIFIER ( "<" IDENTIFIER )? "begin" methodDecl* "end" NEWLINE; methodDecl "class"? function; funDecl "fn" function ; function IDENTIFIER "(" parameters? ")" block ; parameters IDENTIFIER ( "," IDENTIFIER )* ; varDecl "let" IDENTIFIER ("=" expression)? NEWLINE; statement forStmt | ifStmt | returnStmt | whileStmt | exprStmt | block; exprStmt expression NEWLINE; forStmt "for" (classicFor | newFor) statement; classicFor (varDecl | exprStmt | ",") expression? "," expression?; newFor IDENTIFIER ("," IDENTIFIER)? "in" expression; ifStmt "if" expression statement ("elif" expression statement)* ("else" statement)?; returnStmt "return" expression? NEWLINE; whileStmt "while" expression statement; block "begin" NEWLINE declaration* "end" NEWLINE;That's it! The next step is to build a lexer and a parser.