Skip to content

Statements vs Expressions #27

@vlasakm

Description

@vlasakm

Should there be a distinction between statements and expressions? What should be an expression and what a statement? Is the top level to be composed of statements or expressions?

There is also a difference between separators and terminators. For example it is different whether val or def declarations are terminated by semicolons (the semicolon is part of their grammar rule) or like now, they are just statements separated by semicolons (just like any other statements are serparated by semicolons).

Should initial separator be allowed? E.g. the ML / Haskell style:

def fun
(
, aVeryLongArgumentNameThatOnlyFitsOnItsOwnLine
, aVeryLongArgumentNameThatOnlyFitsOnItsOwnLine2
)
= 1;

What should be the behaviour of these block expressions: {}, { f() }, { f(); }?

It seems to me that the syntax is already Scala like, and having "everything as expression" would maybe be simpler.

I originally wanted to submit a PR to allow initial separators and to somewhat solve the block expression. But I wasn't sure what you intended. My understanding of block expressions is:

  • {} = evaluates as None
  • { f() } = evaluates to f()`
  • { f(); } = f() executed but result discarded, the block evaluates to None

This corresponds to the idea that blocks contain expressions separated by semicolons, but trailing separator means implicit None. I don't know whether this is desirable for block expressions or the top level. The idea for implementation is below.

diff --git a/Cacom/src/ast.rs b/Cacom/src/ast.rs
index 5ab4da9..1870251 100644
--- a/Cacom/src/ast.rs
+++ b/Cacom/src/ast.rs
@@ -48,6 +48,12 @@ pub enum AST {
     Expression(Expr),
 }
 
+impl Default for AST {
+    fn default() -> Self {
+        Self::Expression(Expr::NoneVal)
+    }
+}
+
 /// Expressions always leave some value on the stack
 ///
 /// For example, if statement always leaves resulting value
diff --git a/Cacom/src/grammar.lalrpop b/Cacom/src/grammar.lalrpop
index b486327..46025c4 100644
--- a/Cacom/src/grammar.lalrpop
+++ b/Cacom/src/grammar.lalrpop
@@ -160,9 +160,8 @@ String: String = {
 
 Block: Expr = {
     CURLYBOPEN <Statements> CURLYBCLOSE => Expr::Block(<>),
-    CURLYBOPEN CURLYBCLOSE => Expr::NoneVal,
 }
-Statements = SeparatedLeastOne<Statement, SEMICOLON>;
+Statements = SeparatedLastMayDefault<Statement, SEMICOLON>;
 
 FunDecl: AST = {
     DEF <name: Identifier> LPAREN <parameters: Parameters> RPAREN ASSIGN <body: Expr> => {
@@ -184,7 +183,7 @@ Return: AST = {
 
 // Macros
 Separated<T, S>: Vec<T> = {
-    <mut v: (<T> S)*> <e: T?> => match e {
+    <mut v: S? (<T> S)*> <e: T?> => match e {
         None => v,
         Some(e) => { v.push(e); v }
     }
@@ -193,3 +192,14 @@ Separated<T, S>: Vec<T> = {
 SeparatedLeastOne<T, S>: Vec<T> = {
     <mut v: (<T> S)*> <e: T> S? => { v.push(e); v }
 };
+
+SeparatedLastMayDefault<T, S>: Vec<T> = {
+    <mut v: (<T> S)*> <e: T?> => {
+        let e = match e {
+            Some(e) => e,
+            None => Default::default(),
+        };
+        v.push(e);
+        v
+    }
+};

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions