svg-filters & basic parser #15
7 changed files with 136 additions and 8 deletions
|
@ -111,7 +111,7 @@ impl Marker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn complete_node(mut self, p: &mut Parser, kind: NodeKind) -> CompletedMarker {
|
fn close_node(mut self, p: &mut Parser, kind: NodeKind) -> CompletedMarker {
|
||||||
self.bomb.defuse();
|
self.bomb.defuse();
|
||||||
match &mut p.events[self.pos] {
|
match &mut p.events[self.pos] {
|
||||||
Event::Start { kind: slot, .. } => *slot = kind.clone(),
|
Event::Start { kind: slot, .. } => *slot = kind.clone(),
|
||||||
|
@ -127,11 +127,11 @@ impl Marker {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn complete(self, p: &mut Parser<'_, '_>, kind: SyntaxKind) -> CompletedMarker {
|
pub(crate) fn complete(self, p: &mut Parser<'_, '_>, kind: SyntaxKind) -> CompletedMarker {
|
||||||
self.complete_node(p, NodeKind::Syntax(kind))
|
self.close_node(p, NodeKind::Syntax(kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn error(self, p: &mut Parser, kind: SyntaxError) -> CompletedMarker {
|
pub(crate) fn error(self, p: &mut Parser, kind: SyntaxError) -> CompletedMarker {
|
||||||
self.complete_node(p, NodeKind::Error(kind))
|
self.close_node(p, NodeKind::Error(kind))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn abandon(mut self, p: &mut Parser<'_, '_>) {
|
pub(crate) fn abandon(mut self, p: &mut Parser<'_, '_>) {
|
||||||
|
|
|
@ -7,4 +7,7 @@ pub enum SyntaxError {
|
||||||
// if there was two space seperated items in a list
|
// if there was two space seperated items in a list
|
||||||
SpaceSepInList,
|
SpaceSepInList,
|
||||||
SemicolonInList,
|
SemicolonInList,
|
||||||
|
CommaInMatOrVec,
|
||||||
|
UnterminatedTopLevelItem,
|
||||||
|
UnclosedModuleBody,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ use std::fmt::Debug;
|
||||||
|
|
||||||
use crate::lst_parser::syntax_kind::SyntaxKind::*;
|
use crate::lst_parser::syntax_kind::SyntaxKind::*;
|
||||||
|
|
||||||
|
use self::module::{mod_body, top_level_item};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
input::Input,
|
input::Input,
|
||||||
output::Output,
|
output::Output,
|
||||||
|
@ -10,11 +12,13 @@ use super::{
|
||||||
};
|
};
|
||||||
|
|
||||||
mod expression;
|
mod expression;
|
||||||
|
mod module;
|
||||||
|
|
||||||
pub fn source_file(p: &mut Parser) {
|
pub fn source_file(p: &mut Parser) {
|
||||||
let root = p.start("root");
|
let root = p.start("root");
|
||||||
|
|
||||||
expression::expression(p, false);
|
mod_body(p);
|
||||||
|
// expression::expression(p, false);
|
||||||
p.eat_succeeding_ws();
|
p.eat_succeeding_ws();
|
||||||
|
|
||||||
root.complete(p, ROOT);
|
root.complete(p, ROOT);
|
||||||
|
|
|
@ -25,7 +25,6 @@ pub fn vec_matrix_list(p: &mut Parser) -> CompletedMarker {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: handle semicolons, other wrong toks
|
|
||||||
fn finish_list(p: &mut Parser, list_start: Marker) -> CompletedMarker {
|
fn finish_list(p: &mut Parser, list_start: Marker) -> CompletedMarker {
|
||||||
loop {
|
loop {
|
||||||
if p.eat(COMMA) {
|
if p.eat(COMMA) {
|
||||||
|
@ -41,11 +40,11 @@ fn finish_list(p: &mut Parser, list_start: Marker) -> CompletedMarker {
|
||||||
item.precede(p, "next_item")
|
item.precede(p, "next_item")
|
||||||
.complete(p, COLLECTION_ITEM)
|
.complete(p, COLLECTION_ITEM)
|
||||||
.precede(p, "err_space_sep")
|
.precede(p, "err_space_sep")
|
||||||
.complete_err(p, SyntaxError::SpaceSepInList);
|
.error(p, SyntaxError::SpaceSepInList);
|
||||||
} else if p.at(SEMICOLON) {
|
} else if p.at(SEMICOLON) {
|
||||||
let semi_err = p.start("semicolon_err");
|
let semi_err = p.start("semicolon_err");
|
||||||
p.eat(SEMICOLON);
|
p.eat(SEMICOLON);
|
||||||
semi_err.complete_err(p, SyntaxError::SemicolonInList);
|
semi_err.error(p, SyntaxError::SemicolonInList);
|
||||||
if let Some(item) = atom(p) {
|
if let Some(item) = atom(p) {
|
||||||
item.precede(p, "coll_item_start")
|
item.precede(p, "coll_item_start")
|
||||||
.complete(p, COLLECTION_ITEM);
|
.complete(p, COLLECTION_ITEM);
|
||||||
|
@ -85,6 +84,14 @@ fn finish_mat_or_vec(p: &mut Parser, coll_start: Marker, mut row_start: Marker)
|
||||||
p.eat(R_BRACK);
|
p.eat(R_BRACK);
|
||||||
return coll_start.complete(p, VEC);
|
return coll_start.complete(p, VEC);
|
||||||
}
|
}
|
||||||
|
} else if p.at(COMMA) {
|
||||||
|
let err_unexpected_comma = p.start("err_unexpected_comma");
|
||||||
|
p.do_bump();
|
||||||
|
err_unexpected_comma.error(p, SyntaxError::CommaInMatOrVec);
|
||||||
|
} else {
|
||||||
|
let err_unexpected = p.start("err_unexpected_tok");
|
||||||
|
p.do_bump();
|
||||||
|
err_unexpected.error(p, SyntaxError::Expected(vec![EXPR, SEMICOLON, R_BRACK]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
106
crates/lang/src/lst_parser/grammar/module.rs
Normal file
106
crates/lang/src/lst_parser/grammar/module.rs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
use enumset::enum_set;
|
||||||
|
|
||||||
|
use crate::lst_parser::{
|
||||||
|
error::SyntaxError,
|
||||||
|
grammar::expression::expression,
|
||||||
|
syntax_kind::{SyntaxKind::*, TokenSet},
|
||||||
|
CompletedMarker, Parser,
|
||||||
|
};
|
||||||
|
|
||||||
|
const TOP_LEVEL_ITEM_START: TokenSet = enum_set!(DEF_KW | MOD_KW | USE_KW);
|
||||||
|
|
||||||
|
pub fn mod_body(p: &mut Parser) {
|
||||||
|
loop {
|
||||||
|
if top_level_item(p).is_none() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mod_decl(p: &mut Parser) -> Option<CompletedMarker> {
|
||||||
|
let mod_start = p.start("module");
|
||||||
|
if !p.eat(MOD_KW) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mod_name = p.start("module_name");
|
||||||
|
if p.eat(IDENT) {
|
||||||
|
mod_name.complete(p, MODULE_NAME);
|
||||||
|
} else {
|
||||||
|
mod_name.error(p, SyntaxError::Expected(vec![IDENT]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mod_body_marker = p.start("mod_body");
|
||||||
|
if p.eat(SEMICOLON) {
|
||||||
|
mod_body_marker.abandon(p);
|
||||||
|
Some(mod_start.complete(p, MODULE))
|
||||||
|
} else if p.eat(L_BRACE) {
|
||||||
|
mod_body(p);
|
||||||
|
if !p.eat(R_BRACE) {
|
||||||
|
mod_body_marker
|
||||||
|
.complete(p, MODULE_BODY)
|
||||||
|
.precede(p, "unclosed_mod_body_err")
|
||||||
|
.error(p, SyntaxError::UnclosedModuleBody);
|
||||||
|
} else {
|
||||||
|
mod_body_marker.complete(p, MODULE_BODY);
|
||||||
|
}
|
||||||
|
Some(mod_start.complete(p, MODULE))
|
||||||
|
} else {
|
||||||
|
Some(mod_start.error(p, SyntaxError::Expected(vec![MODULE_BODY])))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn top_level_item(p: &mut Parser) -> Option<CompletedMarker> {
|
||||||
|
if !TOP_LEVEL_ITEM_START.contains(p.current()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
def(p).or_else(|| mod_decl(p))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn def(p: &mut Parser) -> Option<CompletedMarker> {
|
||||||
|
let def_start = p.start("top_level_def");
|
||||||
|
if !p.eat(DEF_KW) {
|
||||||
|
def_start.abandon(p);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let def_name = p.start("def_name");
|
||||||
|
if p.eat(IDENT) {
|
||||||
|
def_name.complete(p, DEF_NAME);
|
||||||
|
} else {
|
||||||
|
def_name.error(p, SyntaxError::Expected(vec![IDENT]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let maybe_expected_eq = p.start("maybe_expect_eq");
|
||||||
|
if !p.eat(EQ) {
|
||||||
|
maybe_expected_eq.error(p, SyntaxError::Expected(vec![EQ]));
|
||||||
|
} else {
|
||||||
|
maybe_expected_eq.abandon(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
let body = p.start("def_body");
|
||||||
|
if expression(p, false).is_some() {
|
||||||
|
body.complete(p, DEF_BODY);
|
||||||
|
} else {
|
||||||
|
body.error(p, SyntaxError::Expected(vec![DEF_BODY]));
|
||||||
|
}
|
||||||
|
|
||||||
|
let def = def_start.complete(p, DEF);
|
||||||
|
Some(if p.eat(SEMICOLON) {
|
||||||
|
def
|
||||||
|
} else if TOP_LEVEL_ITEM_START.contains(p.current()) || p.at(EOF) {
|
||||||
|
def.precede(p, "unterminated_tl_item")
|
||||||
|
.error(p, SyntaxError::UnterminatedTopLevelItem)
|
||||||
|
} else {
|
||||||
|
def.precede(p, "err_unexpected")
|
||||||
|
.error(p, SyntaxError::Expected(vec![SEMICOLON]))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn r#use(p: &mut Parser) -> Option<CompletedMarker> {
|
||||||
|
if !p.eat(USE_KW) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
|
@ -30,6 +30,7 @@ pub enum SyntaxKind {
|
||||||
#[token("mod")]
|
#[token("mod")]
|
||||||
MOD_KW,
|
MOD_KW,
|
||||||
MODULE,
|
MODULE,
|
||||||
|
MODULE_NAME,
|
||||||
MODULE_BODY,
|
MODULE_BODY,
|
||||||
#[token("use")]
|
#[token("use")]
|
||||||
USE_KW,
|
USE_KW,
|
||||||
|
|
|
@ -1 +1,8 @@
|
||||||
meow | gay |
|
def hello_world = meow [ 1 2 ]
|
||||||
|
|
||||||
|
def test
|
||||||
|
|
||||||
|
mod hello {
|
||||||
|
def meow = uwu;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue