little bits of progress

This commit is contained in:
JT 2021-07-01 18:09:55 +12:00
parent 43fd0b6ae9
commit 4f89ed5d66
4 changed files with 118 additions and 59 deletions

View File

@ -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;

View File

@ -7,4 +7,5 @@ pub enum ParseError {
UnknownStatement(Span),
Mismatch(String, Span),
VariableNotFound(Span),
UnknownCommand(Span),
}

View File

@ -6,9 +6,16 @@ use crate::{
LiteBlock, LiteCommand, LiteStatement, ParseError, ParserWorkingSet, Span,
};
pub struct Signature {
pub name: String,
pub mandatory_positional: Vec<SyntaxShape>,
}
/// 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<u8>),
/// 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<ParseError>) {
}
fn parse_special_command(&mut self, command: &LiteCommand) -> (Statement, Option<ParseError>) {
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<ParseError>) {
// TODO: add external parsing
(Expression::garbage(spans[0]), None)
}
fn parse_statement(
&mut self,
block: &mut Block,
lite_pipeline: &LiteStatement,
) -> Option<ParseError> {
match lite_pipeline.commands.len() {
0 => None,
1 => None,
_ => {
// pipeline
None
}
pub fn parse_call(&mut self, spans: &[Span]) -> (Expression, Option<ParseError>) {
// 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<ParseError>) {
if let Some(token) = token.strip_prefix("0x") {
@ -272,7 +266,10 @@ impl ParserWorkingSet {
) -> (Expression, Option<ParseError>) {
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)

View File

@ -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<u8>)>,
}
pub enum VarLocation {
CurrentScope,
OuterScope,
vars: Vec<Type>,
decls: Vec<Signature>,
}
#[derive(Clone, Copy, Debug)]
@ -17,26 +15,22 @@ pub enum Type {
}
pub type VarId = usize;
pub type DeclId = usize;
struct ScopeFrame {
vars: HashMap<Vec<u8>, VarId>,
decls: HashMap<Vec<u8>, DeclId>,
}
impl ScopeFrame {
pub fn new() -> Self {
Self {
vars: HashMap::new(),
decls: HashMap::new(),
}
}
}
pub struct ParserWorkingSet {
files: Vec<(String, Vec<u8>)>,
vars: HashMap<VarId, Type>,
permanent_state: Option<Arc<ParserState>>,
scope: Vec<ScopeFrame>,
}
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<ParserState>, 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<u8>) -> usize {
self.files.push((filename, contents));
@ -75,11 +89,20 @@ impl ParserState {
}
}
pub struct ParserWorkingSet {
files: Vec<(String, Vec<u8>)>,
vars: Vec<Type>, // indexed by VarId
decls: Vec<Signature>, // indexed by DeclId
permanent_state: Option<Arc<ParserState>>,
scope: Vec<ScopeFrame>,
}
impl ParserWorkingSet {
pub fn new(permanent_state: Option<Arc<ParserState>>) -> 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<DeclId> {
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<VarId> {
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<u8>, 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)]