Initial parser work

This commit is contained in:
Erin 2021-04-18 16:39:43 +02:00 committed by ondra05
parent 08af75fbda
commit 7026711b64
9 changed files with 125 additions and 59 deletions

View file

@ -0,0 +1,2 @@
var hello = true;
var test;

View file

@ -1,14 +1,14 @@
#![forbid(unsafe_code)]
mod base_55;
mod parser;
mod scanner;
mod tokens;
mod variables;
use clap::{App, Arg};
use scanner::Scanner;
use parser::Parser;
fn main() {
variables::test();
// variables::test();
let matches = App::new("AbleScript")
.version(env!("CARGO_PKG_VERSION"))
@ -29,9 +29,10 @@ fn main() {
// Read file
let source = std::fs::read_to_string(file_path).unwrap();
// Print token type: `value`
let mut scanner = Scanner::new(&source);
scanner.scan();
// Parse
let mut parser = Parser::new(&source);
let ast = parser.parse();
println!("{:#?}", ast);
}
None => {
println!("hi");

View file

@ -1,17 +0,0 @@
use crate::tokens::Abool;
pub fn abool2num(abool: Abool) -> i32 {
match abool {
Abool::Never => -1,
Abool::Sometimes => 0,
Abool::Always => 1,
}
}
pub fn num2abool(number: i32) -> Abool {
match number {
-1 => Abool::Never,
0 => Abool::Sometimes,
1 => Abool::Always,
_ => Abool::Sometimes,
}
}

4
src/parser/item.rs Normal file
View file

@ -0,0 +1,4 @@
#[derive(Debug, Clone)]
pub enum Expr {
DeclareVariable { iden: String, init: Option<String> },
}

68
src/parser/mod.rs Normal file
View file

@ -0,0 +1,68 @@
mod item;
mod utils;
use item::Expr;
use crate::tokens::Token;
use crate::variables::Value;
use logos::Logos;
#[derive(Debug)]
pub enum ParseError {
UnexpectedToken,
LexError,
UnexpectedEOF,
}
/// Parser structure / state machine
pub struct Parser<'a> {
lexer: logos::Lexer<'a, Token>,
ast: Vec<Expr>,
}
impl<'a> Parser<'a> {
/// Create a new parser object
pub fn new(source: &'a str) -> Self {
Self {
lexer: Token::lexer(source),
ast: vec![],
}
}
/// Start parsing Token Vector into Abstract Syntax Tree
pub fn parse(&mut self) -> Vec<Expr> {
while let Some(token) = self.lexer.next() {
let expr = match token {
Token::Variable => self.variable(),
tok => {
// TODO: Better error handling
println!("Parse error");
break;
}
};
self.ast.push(expr.unwrap());
}
self.ast.clone()
}
/// Parse variable declaration
///
/// `var [iden] = [literal];`
fn variable(&mut self) -> Result<Expr, ParseError> {
let iden = self.require(Token::Identifier)?;
let init = match self.lexer.next() {
Some(Token::Semicolon) => None,
Some(Token::Assignment) => {
let value = self.require(Token::Boolean)?; // TODO: Shouldn't be limited to boolean (pattern match?)
self.require(Token::Semicolon)?;
Some(value)
}
_ => return Err(ParseError::UnexpectedToken),
};
Ok(Expr::DeclareVariable { iden, init })
}
}

30
src/parser/utils.rs Normal file
View file

@ -0,0 +1,30 @@
use crate::tokens::{Abool, Token};
use super::{ParseError, Parser};
pub fn abool2num(abool: Abool) -> i32 {
match abool {
Abool::Never => -1,
Abool::Sometimes => 0,
Abool::Always => 1,
}
}
pub fn num2abool(number: i32) -> Abool {
match number {
-1 => Abool::Never,
0 => Abool::Sometimes,
1 => Abool::Always,
_ => Abool::Sometimes,
}
}
impl<'a> Parser<'a> {
/// Require type of token as next and return it's value (sometimes irrelevant)
pub(super) fn require(&mut self, with: Token) -> Result<String, ParseError> {
if self.lexer.next() == Some(with) {
Ok(self.lexer.slice().to_owned())
} else {
Err(ParseError::UnexpectedToken)
}
}
}

View file

@ -1,33 +0,0 @@
use std::ops::Range;
use logos::Logos;
use crate::tokens::{self, Token};
pub struct Scanner<'a> {
source: &'a str,
lexer: logos::Lexer<'a, Token>,
}
impl<'a> Scanner<'a> {
pub fn new(source: &'a str) -> Self {
Self {
source,
lexer: tokens::Token::lexer(source),
}
}
pub fn scan(&mut self) {
while let Some(tok) = self.lexer.next() {
if matches!(tok, Token::Error) {
self.throw_err(&self.lexer.span());
} else {
println!("Token: {:?}", tok);
}
}
}
fn throw_err(&self, location: &Range<usize>) {
let part = &self.source[location.clone()];
println!("Unknown keyword `{}` found on {:?}", part, location);
}
}

View file

@ -30,6 +30,7 @@ pub enum Token {
#[regex(r"#.*")]
Comment,
// Operators
#[token("-")]
Subtract,
@ -87,6 +88,16 @@ pub enum Token {
#[token("T-Dark")]
TDark,
// Expressions
#[token("if")]
If,
#[token("else")]
Else,
#[token("loop")]
Loop,
#[regex(r"[ \t\n\f]+", logos::skip)]
#[error]
Error,

View file

@ -1,7 +1,7 @@
use std::collections::HashMap;
#[derive(Debug)]
enum Value {
#[derive(Debug, Clone)]
pub enum Value {
Str(String),
Int(i32),
Bool(bool),