From 2bea3994c29c9802eef50b166963f4aad15a46a0 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Wed, 24 Apr 2024 19:37:52 +0200 Subject: [PATCH] lang: matrix parser! --- crates/lang/src/parser.rs | 6 ++ crates/lang/src/parser/grammar/expression.rs | 58 ++++++++++++++-- .../grammar/expression/collection/matrix.rs | 69 +++++++++++++++++++ .../parser/grammar/expression/instruction.rs | 10 ++- crates/lang/src/parser/syntax_kind.rs | 8 ++- testfiles/test.owo | 5 +- 6 files changed, 144 insertions(+), 12 deletions(-) create mode 100644 crates/lang/src/parser/grammar/expression/collection/matrix.rs diff --git a/crates/lang/src/parser.rs b/crates/lang/src/parser.rs index e850ab0..996f15a 100644 --- a/crates/lang/src/parser.rs +++ b/crates/lang/src/parser.rs @@ -94,6 +94,7 @@ impl Marker { bomb: DropBomb::new("Marker must be completed or abandoned"), } } + pub(crate) fn complete(mut self, p: &mut Parser<'_, '_>, kind: SyntaxKind) -> CompletedMarker { self.bomb.defuse(); match &mut p.events[self.pos] { @@ -108,6 +109,11 @@ impl Marker { } } + pub(crate) fn complete_err(mut self, p: &mut Parser, kind: SyntaxError) -> CompletedMarker { + p.errors.push(kind); + self.complete(p, SyntaxKind::PARSE_ERR) + } + pub(crate) fn abandon(mut self, p: &mut Parser<'_, '_>) { self.bomb.defuse(); if self.pos == p.events.len() - 1 { diff --git a/crates/lang/src/parser/grammar/expression.rs b/crates/lang/src/parser/grammar/expression.rs index 18323a5..cb1f410 100644 --- a/crates/lang/src/parser/grammar/expression.rs +++ b/crates/lang/src/parser/grammar/expression.rs @@ -1,14 +1,62 @@ -use crate::parser::{syntax_kind::SyntaxKind::*, Parser}; +use crate::parser::{syntax_kind::SyntaxKind::*, CompletedMarker, Parser}; -use self::{instruction::instr, lit::literal}; +use self::{collection::collection, instruction::instr, lit::literal}; mod instruction; mod lit; +mod collection { + use enumset::enum_set; -pub fn expression(p: &mut Parser) { + use crate::parser::{ + syntax_kind::{SyntaxKind::*, TokenSet}, + CompletedMarker, Parser, + }; + + use self::{attr_set::attr_set, matrix::matrix, vec::vec}; + + const COLLECTION_START: TokenSet = enum_set!(MAT_KW | L_BRACK | L_BRACE); + + pub fn collection(p: &mut Parser) -> Option { + if !COLLECTION_START.contains(p.current()) { + return None; + } + + Some(match p.current() { + MAT_KW => matrix(p), + L_BRACK => vec(p), + L_BRACE => attr_set(p), + _ => unreachable!(), + }) + } + + mod matrix; + mod vec { + use crate::parser::{CompletedMarker, Parser}; + + pub fn vec(p: &mut Parser) -> CompletedMarker { + todo!() + } + } + mod attr_set { + use crate::parser::{CompletedMarker, Parser}; + + pub fn attr_set(p: &mut Parser) -> CompletedMarker { + todo!() + } + } +} + +pub fn expression(p: &mut Parser) -> Option { let expr = p.start(); - instr(p); + if atom(p).or_else(|| instr(p)).is_none() { + expr.abandon(p); + return None; + } - expr.complete(p, EXPR); + Some(expr.complete(p, EXPR)) +} + +pub fn atom(p: &mut Parser) -> Option { + literal(p).or_else(|| collection(p)) } diff --git a/crates/lang/src/parser/grammar/expression/collection/matrix.rs b/crates/lang/src/parser/grammar/expression/collection/matrix.rs new file mode 100644 index 0000000..58ba9e1 --- /dev/null +++ b/crates/lang/src/parser/grammar/expression/collection/matrix.rs @@ -0,0 +1,69 @@ +use crate::parser::{ + error::SyntaxError, + grammar::expression::{self, expression}, + syntax_kind::SyntaxKind::*, + CompletedMarker, Marker, Parser, +}; + +pub fn matrix(p: &mut Parser) -> CompletedMarker { + let matrix = p.start(); + p.eat(MAT_KW); + + if !p.eat(PAT_DIMENSIONS) { + eprintln!("TODO (as eprintln so i dont forget): improve recovery algorithms"); + return matrix.complete_err(p, SyntaxError::Expected(vec![PAT_DIMENSIONS])); + } + + matrix_body(p); + + matrix.complete(p, MATRIX) +} + +fn matrix_body(p: &mut Parser) { + let mat_body = p.start(); + if !p.eat(L_BRACK) { + mat_body.complete_err(p, SyntaxError::Expected(vec![MAT_BODY])); + return (); + } + + let mut going = true; + + let mut mat_row = p.start(); + let mut row_items = 0; + while going { + let mat_item = p.start(); + if expression(p).is_some() { + mat_item.complete(p, MAT_ITEM); + row_items += 1; + match p.current() { + COMMA => p.do_bump(), + SEMICOLON => { + mat_row.complete(p, MAT_ROW); + mat_row = p.start(); + p.do_bump(); + row_items = 0; + } + R_BRACK => going = false, + _ => { + let err = p.start(); + p.do_bump(); + + err.complete_err(p, SyntaxError::Expected(vec![COMMA, SEMICOLON, R_BRACK])); + } + }; + } else if p.at(R_BRACK) { + going = false; + } else { + let err = p.start(); + p.do_bump(); + err.complete_err(p, SyntaxError::Expected(vec![EXPR, R_BRACK])); + } + } + if row_items != 0 { + mat_row.complete(p, MAT_ROW); + } else { + mat_row.abandon(p); + } + p.eat(R_BRACK); + mat_body.complete(p, MAT_BODY); +} diff --git a/crates/lang/src/parser/grammar/expression/instruction.rs b/crates/lang/src/parser/grammar/expression/instruction.rs index 136f4ed..5da0f43 100644 --- a/crates/lang/src/parser/grammar/expression/instruction.rs +++ b/crates/lang/src/parser/grammar/expression/instruction.rs @@ -1,14 +1,18 @@ -use crate::parser::{syntax_kind::SyntaxKind::*, Parser}; +use crate::parser::{syntax_kind::SyntaxKind::*, CompletedMarker, Parser}; use super::lit::literal; -pub fn instr(p: &mut Parser) { +pub fn instr(p: &mut Parser) -> Option { + if !p.at(IDENT) { + return None; + } + let instr = p.start(); instr_name(p); instr_params(p); - instr.complete(p, INSTR); + Some(instr.complete(p, INSTR)) } fn instr_name(p: &mut Parser) { diff --git a/crates/lang/src/parser/syntax_kind.rs b/crates/lang/src/parser/syntax_kind.rs index e37254f..cc1754c 100644 --- a/crates/lang/src/parser/syntax_kind.rs +++ b/crates/lang/src/parser/syntax_kind.rs @@ -34,9 +34,11 @@ pub enum SyntaxKind { #[regex(r#""([^"\\]|\\["\\bnfrt]|u[a-fA-F0-9]{4})*""#)] STRING, MATRIX, + MAT_BODY, + MAT_ROW, + MAT_ITEM, DECL, LIST, - MAT_BODY, PARENTHESIZED_EXPR, EXPR, LITERAL, @@ -45,9 +47,9 @@ pub enum SyntaxKind { #[token(")")] R_PAREN, #[token("{")] - L_CURLY, + L_BRACE, #[token("}")] - R_CURLY, + R_BRACE, #[token("[")] L_BRACK, #[token("]")] diff --git a/testfiles/test.owo b/testfiles/test.owo index ab4456d..87a5bc8 100644 --- a/testfiles/test.owo +++ b/testfiles/test.owo @@ -1 +1,4 @@ -hello world test 1.5 42 69 "gay" +mat 2x2 [ + 1, 2; + 3, 4 +]