about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-24 02:03:29 +0200
committerMel <einebeere@gmail.com>2021-10-24 02:03:29 +0200
commit73c4808c44f75b7d6546f00f70779fcbf8e28754 (patch)
treef44e26fad3f37e62c0f5a35e2fafbe2d20f6da55 /src
parent249abe9c33dfd08afa6b09f3e53be91b0f445561 (diff)
downloadrabbithole-73c4808c44f75b7d6546f00f70779fcbf8e28754.tar.zst
rabbithole-73c4808c44f75b7d6546f00f70779fcbf8e28754.zip
Postfix parsing
Diffstat (limited to 'src')
-rw-r--r--src/interpret/walker.rs3
-rw-r--r--src/lex/lexer.rs2
-rw-r--r--src/lex/token.rs2
-rw-r--r--src/parse/ast/expression.rs28
-rw-r--r--src/parse/ast/nodes.rs18
-rw-r--r--src/parse/parser.rs69
6 files changed, 103 insertions, 19 deletions
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index db37a26..ac3a092 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -109,6 +109,9 @@ impl Walker {
 
                 Ok(new_value)
             }
+            Expression::Call(_) => todo!("Calls not implemented yet."),
+            Expression::ArrayAccess(_) => todo!("Arrays not implemented yet."),
+            Expression::MemberAccess(_) => todo!("Structures not implemented yet."),
             Expression::Group(node) => self.walk_expression(node),
             Expression::Literal(token) => {
                 let value = match token {
diff --git a/src/lex/lexer.rs b/src/lex/lexer.rs
index 41384a9..edd1ff0 100644
--- a/src/lex/lexer.rs
+++ b/src/lex/lexer.rs
@@ -83,6 +83,8 @@ impl Iterator for Lexer<'_> {
                 ')' => GroupClose,
                 '{' => BlockOpen,
                 '}' => BlockClose,
+                '[' => ArrayOpen,
+                ']' => ArrayClose,
                 '.' => Dot,
                 ',' => Comma,
                 ':' => {
diff --git a/src/lex/token.rs b/src/lex/token.rs
index 2fb5d5b..3c6d5c6 100644
--- a/src/lex/token.rs
+++ b/src/lex/token.rs
@@ -40,6 +40,8 @@ pub enum TokenVariant {
     GroupClose,
     BlockOpen,
     BlockClose,
+    ArrayOpen,
+    ArrayClose,
 
     // Literals
     Int(u32),
diff --git a/src/parse/ast/expression.rs b/src/parse/ast/expression.rs
index c7f6d9b..1eec69d 100644
--- a/src/parse/ast/expression.rs
+++ b/src/parse/ast/expression.rs
@@ -1,7 +1,8 @@
 use std::fmt::{self, Display, Formatter};
 
 use super::nodes::{
-    BinaryOperator, BlockNode, FnNode, Identifier, IfNode, Literal, LoopNode, UnaryOperator,
+    ArrayAccessNode, BinaryOperator, BlockNode, CallNode, FnNode, Identifier, IfNode, Literal,
+    LoopNode, MemberAccessNode, UnaryOperator,
 };
 
 #[derive(Debug, Clone)]
@@ -15,6 +16,9 @@ pub enum Expression {
         op: UnaryOperator,
         right: Box<Expression>,
     },
+    Call(Box<CallNode>),
+    ArrayAccess(Box<ArrayAccessNode>),
+    MemberAccess(Box<MemberAccessNode>),
     Group(Box<Expression>),
     Block(Box<BlockNode>),
     Fn(Box<FnNode>),
@@ -48,6 +52,28 @@ impl Expression {
                 writeln!(f, "{}- Right:", pad)?;
                 right.nested_fmt(f, depth + 1)?;
             }
+            Expression::Call(node) => {
+                writeln!(f, "{}Function Call:", pad)?;
+                writeln!(f, "{}- Called:", pad)?;
+                node.called.nested_fmt(f, depth + 1)?;
+                for (i, e) in node.arguments.iter().enumerate() {
+                    writeln!(f, "{}- Argument {}:", pad, i)?;
+                    e.nested_fmt(f, depth + 1)?;
+                }
+            }
+            Expression::ArrayAccess(node) => {
+                writeln!(f, "{}Array Access:", pad)?;
+                writeln!(f, "{}- Array:", pad)?;
+                node.array.nested_fmt(f, depth + 1)?;
+                writeln!(f, "{}- Index:", pad)?;
+                node.index.nested_fmt(f, depth + 1)?;
+            }
+            Expression::MemberAccess(node) => {
+                writeln!(f, "{}Member Access:", pad)?;
+                writeln!(f, "{}- Object:", pad)?;
+                node.object.nested_fmt(f, depth + 1)?;
+                writeln!(f, "{}- Member Name: {}", pad, node.member_name)?;
+            }
             Expression::Group(node) => {
                 writeln!(f, "{}Group:", pad)?;
                 node.nested_fmt(f, depth + 1)?;
diff --git a/src/parse/ast/nodes.rs b/src/parse/ast/nodes.rs
index 2a4f7c0..617a01c 100644
--- a/src/parse/ast/nodes.rs
+++ b/src/parse/ast/nodes.rs
@@ -88,6 +88,24 @@ pub struct TypedIdentifier {
 }
 
 #[derive(Debug, Clone)]
+pub struct CallNode {
+    pub called: Expression,
+    pub arguments: Vec<Expression>,
+}
+
+#[derive(Debug, Clone)]
+pub struct ArrayAccessNode {
+    pub array: Expression,
+    pub index: Expression,
+}
+
+#[derive(Debug, Clone)]
+pub struct MemberAccessNode {
+    pub object: Expression,
+    pub member_name: Identifier,
+}
+
+#[derive(Debug, Clone)]
 pub struct FnNode {
     pub header: FnHeader,
     pub body: BlockNode,
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 4a84101..2083f75 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1,24 +1,14 @@
 use super::ast::expression::Expression;
-use super::ast::nodes::LoopNode;
-use super::ast::nodes::UnaryOperator;
+use super::ast::nodes::{LoopNode, UnaryOperator};
 use super::ast::statement::Statement;
 use super::ast::Program;
-use crate::check;
-use crate::consume;
-use crate::consume_if;
-use crate::inner;
-use crate::lex::token::Token;
 use crate::lex::token::TokenVariant::*;
-use crate::parse::ast::nodes::BinaryOperator;
-use crate::parse::ast::nodes::BlockNode;
-use crate::parse::ast::nodes::ConditionalBlock;
-use crate::parse::ast::nodes::FnHeader;
-use crate::parse::ast::nodes::FnNode;
-use crate::parse::ast::nodes::IfNode;
-use crate::parse::ast::nodes::Literal;
-use crate::parse::ast::nodes::TypedIdentifier;
-use anyhow::anyhow;
-use anyhow::Result;
+use crate::parse::ast::nodes::{
+    ArrayAccessNode, BinaryOperator, BlockNode, CallNode, ConditionalBlock, FnHeader, FnNode,
+    IfNode, Literal, MemberAccessNode, TypedIdentifier,
+};
+use crate::{check, consume, consume_if, inner, lex::token::Token};
+use anyhow::{anyhow, Result};
 use std::iter::Peekable;
 
 pub struct Parser<T: Iterator> {
@@ -183,12 +173,55 @@ impl<T: Iterator<Item = Token>> Parser<T> {
                 right: Box::new(self.unary_expression()?),
             }
         } else {
-            self.unit_expression()?
+            self.postfix_expression()?
         };
 
         Ok(expression)
     }
 
+    fn postfix_expression(&mut self) -> Result<Expression> {
+        let mut left = self.unit_expression()?;
+
+        while let Some(token) = consume_if!(self, GroupOpen | ArrayOpen | Dot) {
+            match token.variant {
+                GroupOpen => loop {
+                    let mut arguments = Vec::new();
+
+                    loop {
+                        arguments.push(self.expression()?);
+
+                        if consume_if!(self, Comma).is_none() {
+                            consume!(self, GroupClose)?;
+                            break;
+                        }
+                    }
+
+                    left = Expression::Call(Box::new(CallNode {
+                        called: left,
+                        arguments,
+                    }))
+                },
+                ArrayOpen => {
+                    let index = self.expression()?;
+                    consume!(self, ArrayClose)?;
+
+                    left = Expression::ArrayAccess(Box::new(ArrayAccessNode { array: left, index }))
+                }
+                Dot => {
+                    let member_name = inner!(consume!(self, Ident(_))?, Ident);
+
+                    left = Expression::MemberAccess(Box::new(MemberAccessNode {
+                        object: left,
+                        member_name,
+                    }))
+                }
+                _ => unreachable!(),
+            }
+        }
+
+        Ok(left)
+    }
+
     fn unit_expression(&mut self) -> Result<Expression> {
         if let Some(token) = self.tokens.peek() {
             match token.variant {