diff --git a/src/lib.rs b/src/lib.rs index 36d336dd88..b42c4c684b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,5 +8,5 @@ mod span; pub use lex::{lex, LexMode, Token, TokenContents}; pub use lite_parse::{lite_parse, LiteBlock, LiteCommand, LiteStatement}; pub use parse_error::ParseError; -pub use parser_state::{ParserState, ParserWorkingSet, VarLocation}; +pub use parser_state::{ParserState, ParserWorkingSet}; pub use span::Span; diff --git a/src/parse_error.rs b/src/parse_error.rs index d242f870d7..c9bfb3f3e6 100644 --- a/src/parse_error.rs +++ b/src/parse_error.rs @@ -7,4 +7,5 @@ pub enum ParseError { UnknownStatement(Span), Mismatch(String, Span), VariableNotFound(Span), + UnknownCommand(Span), } diff --git a/src/parser.rs b/src/parser.rs index a77a912aff..3115c53a7c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -6,9 +6,16 @@ use crate::{ LiteBlock, LiteCommand, LiteStatement, ParseError, ParserWorkingSet, Span, }; +pub struct Signature { + pub name: String, + pub mandatory_positional: Vec, +} + /// The syntactic shapes that values must match to be passed into a command. You can think of this as the type-checking that occurs when you call a function. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Clone)] pub enum SyntaxShape { + /// A specific match to a word or symbol + Word(Vec), /// Any syntactic form is allowed Any, /// Strings and string-like bare words are allowed @@ -154,39 +161,26 @@ fn span(spans: &[Span]) -> Span { } impl ParserWorkingSet { - /* - fn parse_let(&mut self, command: &LiteCommand) -> (Statement, Option) { - - } - fn parse_special_command(&mut self, command: &LiteCommand) -> (Statement, Option) { - let command_name = self.get_span_contents(command.parts[0]); - println!("{:?}", command_name); - match command_name { - b"let" => self.parse_let(command), - b"def" => self.parse_def(command), - b"source" => self.parse_source(command), - _ => ( - Statement::None, - Some(ParseError::UnknownStatement(command.parts[0])), - ), - } + pub fn parse_external_call(&mut self, spans: &[Span]) -> (Expression, Option) { + // TODO: add external parsing + (Expression::garbage(spans[0]), None) } - fn parse_statement( - &mut self, - block: &mut Block, - lite_pipeline: &LiteStatement, - ) -> Option { - match lite_pipeline.commands.len() { - 0 => None, - 1 => None, - _ => { - // pipeline - None - } + pub fn parse_call(&mut self, spans: &[Span]) -> (Expression, Option) { + // assume spans.len() > 0? + let name = self.get_span_contents(spans[0]); + + if let Some(decl_id) = self.find_decl(name) { + let sig = self.get_decl(decl_id).expect("internal error: bad DeclId"); + + let mut positional_idx = 0; + let mut arg_offset = 1; + + (Expression::garbage(spans[0]), None) + } else { + self.parse_external_call(spans) } } - */ pub fn parse_int(&mut self, token: &str, span: Span) -> (Expression, Option) { if let Some(token) = token.strip_prefix("0x") { @@ -272,7 +266,10 @@ impl ParserWorkingSet { ) -> (Expression, Option) { let bytes = self.get_span_contents(span); if !bytes.is_empty() && bytes[0] == b'$' { - if let Some((var_id, _, ty)) = self.find_variable(bytes) { + if let Some(var_id) = self.find_variable(bytes) { + let ty = *self + .get_variable(var_id) + .expect("internal error: invalid VarId"); return ( Expression { expr: Expr::Var(var_id), @@ -316,7 +313,7 @@ impl ParserWorkingSet { let bytes = self.get_span_contents(span); if is_variable(bytes) { - if let Some((var_id, _, _)) = self.find_variable(bytes) { + if let Some(var_id) = self.find_variable(bytes) { (Some(var_id), None) } else { (None, None) diff --git a/src/parser_state.rs b/src/parser_state.rs index b7cdf2a35e..8b7e692db5 100644 --- a/src/parser_state.rs +++ b/src/parser_state.rs @@ -1,13 +1,11 @@ -use crate::{ParseError, Span}; +use crate::{parser::Signature, ParseError, Span}; +use core::num; use std::{collections::HashMap, sync::Arc}; pub struct ParserState { files: Vec<(String, Vec)>, -} - -pub enum VarLocation { - CurrentScope, - OuterScope, + vars: Vec, + decls: Vec, } #[derive(Clone, Copy, Debug)] @@ -17,26 +15,22 @@ pub enum Type { } pub type VarId = usize; +pub type DeclId = usize; struct ScopeFrame { vars: HashMap, VarId>, + decls: HashMap, DeclId>, } impl ScopeFrame { pub fn new() -> Self { Self { vars: HashMap::new(), + decls: HashMap::new(), } } } -pub struct ParserWorkingSet { - files: Vec<(String, Vec)>, - vars: HashMap, - permanent_state: Option>, - scope: Vec, -} - impl Default for ParserState { fn default() -> Self { Self::new() @@ -45,7 +39,11 @@ impl Default for ParserState { impl ParserState { pub fn new() -> Self { - Self { files: vec![] } + Self { + files: vec![], + vars: vec![], + decls: vec![], + } } pub fn merge_working_set(this: &mut Arc, mut working_set: ParserWorkingSet) { @@ -64,6 +62,22 @@ impl ParserState { self.files.len() } + pub fn num_vars(&self) -> usize { + self.vars.len() + } + + pub fn num_decls(&self) -> usize { + self.decls.len() + } + + pub fn get_var(&self, var_id: VarId) -> Option<&Type> { + self.vars.get(var_id) + } + + pub fn get_decl(&self, decl_id: VarId) -> Option<&Signature> { + self.decls.get(decl_id) + } + pub(crate) fn add_file(&mut self, filename: String, contents: Vec) -> usize { self.files.push((filename, contents)); @@ -75,11 +89,20 @@ impl ParserState { } } +pub struct ParserWorkingSet { + files: Vec<(String, Vec)>, + vars: Vec, // indexed by VarId + decls: Vec, // indexed by DeclId + permanent_state: Option>, + scope: Vec, +} + impl ParserWorkingSet { pub fn new(permanent_state: Option>) -> Self { Self { files: vec![], - vars: HashMap::new(), + vars: vec![], + decls: vec![], permanent_state, scope: vec![], } @@ -122,17 +145,29 @@ impl ParserWorkingSet { self.scope.push(ScopeFrame::new()); } - pub fn find_variable(&self, name: &[u8]) -> Option<(VarId, VarLocation, Type)> { + pub fn find_decl(&self, name: &[u8]) -> Option { + for scope in self.scope.iter().rev().enumerate() { + if let Some(decl_id) = scope.1.decls.get(name) { + return Some(*decl_id); + } + } + + None + } + + pub fn next_var_id(&self) -> VarId { + if let Some(permanent_state) = &self.permanent_state { + let num_permanent_vars = permanent_state.num_vars(); + num_permanent_vars + self.vars.len() + } else { + self.vars.len() + } + } + + pub fn find_variable(&self, name: &[u8]) -> Option { for scope in self.scope.iter().rev().enumerate() { if let Some(var_id) = scope.1.vars.get(name) { - if let Some(result) = self.vars.get(var_id) { - if scope.0 == 0 { - // Top level - return Some((*var_id, VarLocation::CurrentScope, *result)); - } else { - return Some((*var_id, VarLocation::OuterScope, *result)); - } - } + return Some(*var_id); } } @@ -140,19 +175,45 @@ impl ParserWorkingSet { } pub fn add_variable(&mut self, name: Vec, ty: Type) -> VarId { + let next_id = self.next_var_id(); + let last = self .scope .last_mut() .expect("internal error: missing stack frame"); - let next_id = self.vars.len(); - last.vars.insert(name, next_id); self.vars.insert(next_id, ty); next_id } + + pub fn get_variable(&self, var_id: VarId) -> Option<&Type> { + if let Some(permanent_state) = &self.permanent_state { + let num_permanent_vars = permanent_state.num_vars(); + if var_id < num_permanent_vars { + permanent_state.get_var(var_id) + } else { + self.vars.get(var_id - num_permanent_vars) + } + } else { + self.vars.get(var_id) + } + } + + pub fn get_decl(&self, decl_id: DeclId) -> Option<&Signature> { + if let Some(permanent_state) = &self.permanent_state { + let num_permanent_decls = permanent_state.num_decls(); + if decl_id < num_permanent_decls { + permanent_state.get_decl(decl_id) + } else { + self.decls.get(decl_id - num_permanent_decls) + } + } else { + self.decls.get(decl_id) + } + } } #[cfg(test)]