diff options
| author | Cliff Click <cliffc@acm.org> | 2024-10-21 09:25:15 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-08-10 11:11:18 -0700 |
| commit | 8c8baca922a9045c09d9d55071d4756ca30e10b7 (patch) | |
| tree | 89674b431279eb4df246f9eb2547c26be1a6d574 /docs/chapter17 | |
| parent | a8891836852f0b2f6f4e1bca5a46c3a899e3ce07 (diff) | |
| download | Simple-8c8baca922a9045c09d9d55071d4756ca30e10b7.tar.gz Simple-8c8baca922a9045c09d9d55071d4756ca30e10b7.zip | |
Chapter 17: Syntax Sugar
Co-authored-by: Tamás Hadházy <85063808+Hels15@users.noreply.github.com>
Co-authored-by: tannal <tannal2409@gmail.com>
Co-authored-by: hadha <helsgithub15@gmail.com>
Co-authored-by: RobertObkircher <robert.obkircher@gmail.com>
Co-authored-by: Hsiang-Ying Fu <66062782+fuhsnn@users.noreply.github.com>
Diffstat (limited to 'docs/chapter17')
| -rw-r--r-- | docs/chapter17/17-grammar.md | 132 | ||||
| -rw-r--r-- | docs/chapter17/Makefile | 12 | ||||
| -rw-r--r-- | docs/chapter17/README.md | 162 |
3 files changed, 306 insertions, 0 deletions
diff --git a/docs/chapter17/17-grammar.md b/docs/chapter17/17-grammar.md new file mode 100644 index 00000000..7b611fbf --- /dev/null +++ b/docs/chapter17/17-grammar.md @@ -0,0 +1,132 @@ +# Grammar for Chapter 16 + +```antlrv4 +grammar SimpleLanguage; + +program : block EOF ; + +block : statement+ ; + + +statement + : '{' block '}' + | returnStatement + | ifStatement + | whileStatement + | breakStatement + | continueStatement + | metaStatement + | structDeclaration + | expressionStatement + ; + + +returnStatement : 'return' expression ';' ; + +ifStatement : 'if' '(' expression ')' statement ('else' statement)? ; + +whileStatement : 'while' '(' expression ')' statement ; + +breakStatement : 'break' ';' ; + +continueStatement : 'continue' ';' ; + +metaStatement : '#showGraph' ';' ; + +structDeclaration : 'struct' IDENTIFIER '{' block '}' ; + +expressionStatement + : type IDENTIFIER ';' + | type IDENTIFIER '=' expression ';' + | IDENTIFIER '=' expression ';' + | expression + ; + +PRIMTYPE + : 'int' + | 'i8' + | 'i16' + | 'i32' + | 'i64' + | 'u8' + | 'u16' + | 'u32' + | 'flt' + | 'f32' + | 'f64' + | 'bool' + ; + +type + : PRIMTYPE + | typeName '?'? + | typeName nestedArray+ + ; + +nestedArray : '?'? '[]'* ; + +typeName : IDENTIFIER ; + + +expression : bitWiseExpression ; + +bitWiseExpression + : comparisonExpression ( '&' | '|' | '^' ) comparisonExpression)* + ; + +comparisonExpression + : shiftExpression (('==' | '!='| '>'| '<'| '>='| '<=') shiftExpression)* + ; + +shiftExpression + : additiveExpression ( '<<' | '>>>' | '>>' ) additiveExpression)* + ; + +additiveExpression + : multiplicativeExpression (('+' | '-') multiplicativeExpression)* + ; + +multiplicativeExpression + : unaryExpression (('*' | '/') unaryExpression)* + ; + +unaryExpression + : ('-') unaryExpression + | '!' unaryExpression + | primaryExpression postAssign + ; + +primaryExpression + : INTEGER_LITERAL + | FLOAT_LITERAL + | '(' expression ')' + | 'true' + | 'false' + | 'null' + | newExpression + | IDENTIFIER + ; + +newExpression + : 'new' IDENTIFIER [ '{' block '}' ] + | 'new' IDENTIFIER '[' expression ']' + ; + +postAssign : postFix [ '=' expression ] | [ '#' ]; + +postFix + : '.' IDENTIFIER postFix + | '[' expression ']' postFix + ; + + +IDENTIFIER : NON_DIGIT (NON_DIGIT | DIGIT)* ; + +INTEGER_LITERAL + : [1-9]DIGIT* + | [0] + ; + +NON_DIGIT: [a-zA-Z_]; +DIGIT: [0-9]; +``` diff --git a/docs/chapter17/Makefile b/docs/chapter17/Makefile new file mode 100644 index 00000000..12659b8f --- /dev/null +++ b/docs/chapter17/Makefile @@ -0,0 +1,12 @@ +GV := $(wildcard *.gv) +SVG := $(patsubst %.gv,%.svg,$(GV)) + +.PHONY: all +all: $(SVG) + +%.svg: %.gv + dot -Tsvg $< > $@ + +.PHONY: clean +clean: + @rm -f $(SVG) diff --git a/docs/chapter17/README.md b/docs/chapter17/README.md new file mode 100644 index 00000000..331cdc3d --- /dev/null +++ b/docs/chapter17/README.md @@ -0,0 +1,162 @@ +# Chapter 17: Syntax Sugar + + +1. [Pre/Post-increment](#prepost-increment) +2. [Operator assignment](#operator-assignment) +3. [var/val](#var--val) + - [Example(1)](#example1) + - [Example(2)](#example2) +4. [Mutability](#mutability) +5. [Reference immutability](#reference-variables-with-an-initializer-are-deeply-immutable) +6. [Trinary](#trinary) +7. [For Loops](#for-loops) + +## Pre/Post-increment + +Allow `arg++` and `arg--` with the usual meanings; the value is updated and the +expression is the pre-update value. Greedy match is used so `arg---arg` parses +as `(arg--)-arg`. + +Also allows `s.fld++` and `ary[idx]++`, and their `--` variants. + +Allow pre-increment for identifiers only, for now: `--pc`. + + +## Operator assignment + +Along the same lines as post-increment, we now allow `op=` assignment +with semantics similar to other languages. + +`x += y` + + +## var & val + +`var` can be used in the `type` position to indicate a "variable" (mutable +value), whose type will be inferred from the required initalizing expression. + +`val` is the same as `var`, except it is a "value" (not mutable). + +The inferred value is the Greatest Lower Bound `glb` type of the peephole type, +which means `var` and `val` will not infer types like `u8` or `f32`, instead +inferring `int` and `flt` respectively. Reference types will always infer as +nullable, so e.g. + +`var s = new S;` + +infers as + +`S s? = new S;` + + +## Mutability + +Typed primitive fields are always mutable. Typed reference fields without an +initializer must be mutable to get a value. Initialized reference variables +are immutable by default and can be made mutable with a leading `!`. Contrast +this with what [chapter16](https://github.com/SeaOfNodes/Simple/tree/chapter16) +did with `!`. `var` and `val` keep their current sense and can be used to make +any field mutable or immutable. Fields are always mutable during construction, +but will become immutable at the end of either constructor. + +`int x; x=3; x++; // OK, primitive so mutable` + +`int x =3; x++; // Ok, primitive so mutable, despite initializer` + +Assume in the next examples this struct exists: +`struct S { int x; };` + +Then: + +`S s; s = new S ; s.x++; // OK, no initializer so s.x is mutable` + +`S s; s = new S{x=3}; s.x++; // OK, no initializer so s.x is mutable` + +`S s = new S ; s.x++; // Error, initializer so s.x is immutable` + +`S s = new S{x=3}; s.x++; // Error, initializer so s.x is immutable` + +Leading `!` makes mutable: + +`S !s = new S; s.x++; // Ok, has '!' so mutable` + +`var` is variable, i.e. mutable: + +`var s = new S; s.x++; // Ok, has var so mutable` + +`val` is a "value": not mutable through this reference, but may be mutable +through other references. + +`val s = new S; s.x++; // Error, val so s.x is immutable` + + +### Reference variables with an initializer are deeply immutable + +Initialized reference variables are deeply immutable, but a mutable version of the same +reference can exist. This works for `val` and normal type declarations: `val s += new S;` and `S s = new S` both make `s` an immutable reference to a `struct S`. + +```cpp +struct Bar { int x; } +Bar !bar = new Bar; // '!' so bar is mutable +bar.x = 3; // Ok, bar is mutable + +struct Foo { Bar !bar; int y; } +Foo !foo = new Foo; // '!' so foo is mutable +foo.bar = bar; // Ok foo is mutable +foo.bar.x++; // Ok foo and foo.bar and foo.bar.x are all mutable + +val xfoo = foo; // Throw away mutability deeply on foo +xfoo.bar.x++; // Error, cannot mutate through xfoo + +print(xfoo.bar.x); // Ok to read through xfoo, prints 4 +foo.bar.x++; // Bumps to 5 +print(xfoo.bar.x); // Ok to read through xfoo, prints 5 +``` + +## Trinary + +Allow `pred ? e_true : e_false`. Also allow `pred ? e_true`, where the false result +is the zero type version of the true result. + + +## For Loops + +Allow C/C++ style `for` loops: + +`for( init; test; next ) body` + +Example: + +```cpp +int sum=0; +for( int i=0; i<arg; i++ ) + sum += i; +return sum; +``` + +Any of `init`, `test` and `next` can be empty. `init` allows for declaration +of a new variable, with scope limited to the `for` expression. + +```cpp +int sum=0; +for( int i=0; i<arg; i++ ) + sum += i; +return i; // ERROR: Undefined name 'i' +``` + +A broken `find` call: +```cpp +for( int i=0; i<ary#; i++ ) + if( ary[i]==e ) + break; +do_stuff(i); // ERROR: undefined name 'i' +``` + +An example `find` call: +```cpp +for( int i=0; i<ary#; i++ ) + if( ary[i]==e ) + return i; +return -1; +```
\ No newline at end of file |
