Run rustfmt on the rest of them
This commit is contained in:
parent
e1d07b4e66
commit
3063de1242
34
src/main.rs
34
src/main.rs
@ -11,23 +11,24 @@ use simplerepl::{REPL, ReplState};
|
|||||||
use tokenizer::tokenize;
|
use tokenizer::tokenize;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
|
|
||||||
use parser::{parse};
|
use parser::parse;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
use eval::{Evaluator};
|
use eval::Evaluator;
|
||||||
mod eval;
|
mod eval;
|
||||||
|
|
||||||
use compilation::{compilation_sequence};
|
use compilation::compilation_sequence;
|
||||||
mod compilation;
|
mod compilation;
|
||||||
mod llvm_wrap;
|
mod llvm_wrap;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let option_matches = program_options().parse(std::env::args()).expect("Could not parse options");
|
let option_matches =
|
||||||
|
program_options().parse(std::env::args()).expect("Could not parse options");
|
||||||
match option_matches.free[..] {
|
match option_matches.free[..] {
|
||||||
[] | [_] => {
|
[] | [_] => {
|
||||||
run_repl();
|
run_repl();
|
||||||
},
|
}
|
||||||
[_, ref filename, ..] => {
|
[_, ref filename, _..] => {
|
||||||
run_noninteractive(filename, !option_matches.opt_present("i"));
|
run_noninteractive(filename, !option_matches.opt_present("i"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -35,7 +36,9 @@ fn main() {
|
|||||||
|
|
||||||
fn program_options() -> getopts::Options {
|
fn program_options() -> getopts::Options {
|
||||||
let mut options = getopts::Options::new();
|
let mut options = getopts::Options::new();
|
||||||
options.optflag("i", "interpret", "Interpret source file instead of compiling");
|
options.optflag("i",
|
||||||
|
"interpret",
|
||||||
|
"Interpret source file instead of compiling");
|
||||||
options
|
options
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,8 +81,7 @@ fn run_repl() {
|
|||||||
show_parse: false,
|
show_parse: false,
|
||||||
evaluator: Evaluator::new(),
|
evaluator: Evaluator::new(),
|
||||||
};
|
};
|
||||||
REPL::with_prompt_and_state(Box::new(repl_handler), ">> ", initial_state)
|
REPL::with_prompt_and_state(Box::new(repl_handler), ">> ", initial_state).run();
|
||||||
.run();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InterpreterState {
|
struct InterpreterState {
|
||||||
@ -93,17 +95,17 @@ impl ReplState for InterpreterState {
|
|||||||
match input[..] {
|
match input[..] {
|
||||||
["set", "show", "tokens", "true"] => {
|
["set", "show", "tokens", "true"] => {
|
||||||
self.show_tokens = true;
|
self.show_tokens = true;
|
||||||
},
|
}
|
||||||
["set", "show", "tokens", "false"] => {
|
["set", "show", "tokens", "false"] => {
|
||||||
self.show_tokens = false;
|
self.show_tokens = false;
|
||||||
},
|
}
|
||||||
["set", "show", "parse", "true"] => {
|
["set", "show", "parse", "true"] => {
|
||||||
self.show_parse = true;
|
self.show_parse = true;
|
||||||
},
|
}
|
||||||
["set", "show", "parse", "false"] => {
|
["set", "show", "parse", "false"] => {
|
||||||
self.show_parse = false;
|
self.show_parse = false;
|
||||||
},
|
}
|
||||||
_ => ()
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,7 +115,7 @@ fn repl_handler(input: &str, state: &mut InterpreterState) -> String {
|
|||||||
|
|
||||||
let tokens = match tokenize(input) {
|
let tokens = match tokenize(input) {
|
||||||
Err(e) => return format!("Tokenization error"),
|
Err(e) => return format!("Tokenization error"),
|
||||||
Ok(t) => t
|
Ok(t) => t,
|
||||||
};
|
};
|
||||||
|
|
||||||
if state.show_tokens {
|
if state.show_tokens {
|
||||||
@ -131,7 +133,7 @@ fn repl_handler(input: &str, state: &mut InterpreterState) -> String {
|
|||||||
|
|
||||||
let mut output: Vec<String> = state.evaluator.run(ast);
|
let mut output: Vec<String> = state.evaluator.run(ast);
|
||||||
|
|
||||||
//for now only handle last output
|
// for now only handle last output
|
||||||
let interpreter_result = output.pop().unwrap_or("".to_string());
|
let interpreter_result = output.pop().unwrap_or("".to_string());
|
||||||
result.push_str(&interpreter_result);
|
result.push_str(&interpreter_result);
|
||||||
result
|
result
|
||||||
|
@ -1,23 +1,23 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use tokenizer::{Token, Kw, Op};
|
use tokenizer::{Token, Kw, Op};
|
||||||
|
|
||||||
/* Grammar
|
// Grammar
|
||||||
program := (statement delimiter ?)*
|
// program := (statement delimiter ?)*
|
||||||
delimiter := Newline | Semicolon
|
// delimiter := Newline | Semicolon
|
||||||
statement := declaration | expression
|
// statement := declaration | expression
|
||||||
declaraion := Fn prototype (statement)* End
|
// declaraion := Fn prototype (statement)* End
|
||||||
prototype := identifier LParen identlist RParen
|
// prototype := identifier LParen identlist RParen
|
||||||
identlist := Ident (Comma Ident)* | e
|
// identlist := Ident (Comma Ident)* | e
|
||||||
exprlist := Expression (Comma Expression)* | e
|
// exprlist := Expression (Comma Expression)* | e
|
||||||
|
//
|
||||||
expression := primary_expression (op primary_expression)*
|
// expression := primary_expression (op primary_expression)*
|
||||||
primary_expression := Number | String | identifier_expr | paren_expr | conditional_expr
|
// primary_expression := Number | String | identifier_expr | paren_expr | conditional_expr
|
||||||
identifier_expr := call_expression | Variable
|
// identifier_expr := call_expression | Variable
|
||||||
paren_expr := LParen expression RParen
|
// paren_expr := LParen expression RParen
|
||||||
call_expr := Identifier LParen exprlist RParen
|
// call_expr := Identifier LParen exprlist RParen
|
||||||
conditional_expr := IF expression THEN (expression delimiter?)* ELSE (expresion delimiter?)* END
|
// conditional_expr := IF expression THEN (expression delimiter?)* ELSE (expresion delimiter?)* END
|
||||||
op := '+', '-', etc.
|
// op := '+', '-', etc.
|
||||||
*/
|
//
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ASTNode {
|
pub enum ASTNode {
|
||||||
@ -34,7 +34,7 @@ pub struct Function {
|
|||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Prototype {
|
pub struct Prototype {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub parameters: Vec<String>
|
pub parameters: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@ -74,12 +74,12 @@ pub type AST = Vec<ASTNode>;
|
|||||||
|
|
||||||
type Precedence = u8;
|
type Precedence = u8;
|
||||||
|
|
||||||
//TODO make this support incomplete parses
|
// TODO make this support incomplete parses
|
||||||
pub type ParseResult<T> = Result<T, ParseError>;
|
pub type ParseResult<T> = Result<T, ParseError>;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ParseError {
|
pub struct ParseError {
|
||||||
pub msg: String
|
pub msg: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParseError {
|
impl ParseError {
|
||||||
@ -103,7 +103,7 @@ impl Parser {
|
|||||||
self.tokens.last().map(|x| x.clone())
|
self.tokens.last().map(|x| x.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Token>{
|
fn next(&mut self) -> Option<Token> {
|
||||||
self.tokens.pop()
|
self.tokens.pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ fn is_delimiter(token: &Token) -> bool {
|
|||||||
use tokenizer::Token::*;
|
use tokenizer::Token::*;
|
||||||
match *token {
|
match *token {
|
||||||
Newline | Semicolon => true,
|
Newline | Semicolon => true,
|
||||||
_ => false
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,14 +159,17 @@ impl Parser {
|
|||||||
let mut ast = Vec::new(); //TODO have this come from previously-parsed tree
|
let mut ast = Vec::new(); //TODO have this come from previously-parsed tree
|
||||||
loop {
|
loop {
|
||||||
let result: ParseResult<ASTNode> = match self.peek() {
|
let result: ParseResult<ASTNode> = match self.peek() {
|
||||||
Some(ref t) if is_delimiter(&t) => { self.next(); continue},
|
Some(ref t) if is_delimiter(&t) => {
|
||||||
|
self.next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Some(_) => self.statement(),
|
Some(_) => self.statement(),
|
||||||
None => break,
|
None => break,
|
||||||
};
|
};
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(node) => ast.push(node),
|
Ok(node) => ast.push(node),
|
||||||
Err(err) => return Err(err)
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +193,10 @@ impl Parser {
|
|||||||
let prototype = try!(self.prototype());
|
let prototype = try!(self.prototype());
|
||||||
let body: Vec<Expression> = try!(self.body());
|
let body: Vec<Expression> = try!(self.body());
|
||||||
expect!(self, Keyword(Kw::End));
|
expect!(self, Keyword(Kw::End));
|
||||||
Ok(ASTNode::FuncNode(Function { prototype: prototype, body: body } ))
|
Ok(ASTNode::FuncNode(Function {
|
||||||
|
prototype: prototype,
|
||||||
|
body: body,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prototype(&mut self) -> ParseResult<Prototype> {
|
fn prototype(&mut self) -> ParseResult<Prototype> {
|
||||||
@ -199,7 +205,10 @@ impl Parser {
|
|||||||
expect!(self, LParen);
|
expect!(self, LParen);
|
||||||
let parameters: Vec<String> = try!(self.identlist());
|
let parameters: Vec<String> = try!(self.identlist());
|
||||||
expect!(self, RParen);
|
expect!(self, RParen);
|
||||||
Ok(Prototype {name: name, parameters: parameters})
|
Ok(Prototype {
|
||||||
|
name: name,
|
||||||
|
parameters: parameters,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn identlist(&mut self) -> ParseResult<Vec<String>> {
|
fn identlist(&mut self) -> ParseResult<Vec<String>> {
|
||||||
@ -240,7 +249,10 @@ impl Parser {
|
|||||||
let mut exprs = Vec::new();
|
let mut exprs = Vec::new();
|
||||||
loop {
|
loop {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
Some(ref t) if is_delimiter(t) => { self.next(); continue},
|
Some(ref t) if is_delimiter(t) => {
|
||||||
|
self.next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Some(Keyword(Kw::End)) => break,
|
Some(Keyword(Kw::End)) => break,
|
||||||
_ => {
|
_ => {
|
||||||
let expr = try!(self.expression());
|
let expr = try!(self.expression());
|
||||||
@ -256,7 +268,10 @@ impl Parser {
|
|||||||
self.precedence_expr(lhs, 0)
|
self.precedence_expr(lhs, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn precedence_expr(&mut self, mut lhs: Expression, min_precedence: u8) -> ParseResult<Expression> {
|
fn precedence_expr(&mut self,
|
||||||
|
mut lhs: Expression,
|
||||||
|
min_precedence: u8)
|
||||||
|
-> ParseResult<Expression> {
|
||||||
use tokenizer::Token::*;
|
use tokenizer::Token::*;
|
||||||
while let Some(Operator(op)) = self.peek() {
|
while let Some(Operator(op)) = self.peek() {
|
||||||
let precedence = self.get_precedence(&op);
|
let precedence = self.get_precedence(&op);
|
||||||
@ -284,13 +299,22 @@ impl Parser {
|
|||||||
fn primary_expression(&mut self) -> ParseResult<Expression> {
|
fn primary_expression(&mut self) -> ParseResult<Expression> {
|
||||||
use tokenizer::Token::*;
|
use tokenizer::Token::*;
|
||||||
Ok(match self.peek() {
|
Ok(match self.peek() {
|
||||||
Some(Keyword(Kw::Null)) => { self.next(); Expression::Null },
|
Some(Keyword(Kw::Null)) => {
|
||||||
Some(NumLiteral(n)) => { self.next(); Expression::Number(n) },
|
self.next();
|
||||||
Some(StrLiteral(s)) => { self.next(); Expression::StringLiteral(s) },
|
Expression::Null
|
||||||
Some(Identifier(_)) => { try!(self.identifier_expr()) },
|
}
|
||||||
Some(Token::LParen) => { try!(self.paren_expr()) }
|
Some(NumLiteral(n)) => {
|
||||||
|
self.next();
|
||||||
|
Expression::Number(n)
|
||||||
|
}
|
||||||
|
Some(StrLiteral(s)) => {
|
||||||
|
self.next();
|
||||||
|
Expression::StringLiteral(s)
|
||||||
|
}
|
||||||
|
Some(Identifier(_)) => try!(self.identifier_expr()),
|
||||||
|
Some(Token::LParen) => try!(self.paren_expr()),
|
||||||
Some(_) => return ParseError::result_from_str("Expected primary expression"),
|
Some(_) => return ParseError::result_from_str("Expected primary expression"),
|
||||||
None => return ParseError::result_from_str("Expected primary expression received EoI")
|
None => return ParseError::result_from_str("Expected primary expression received EoI"),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -301,8 +325,8 @@ impl Parser {
|
|||||||
Some(LParen) => {
|
Some(LParen) => {
|
||||||
let args = try!(self.call_expr());
|
let args = try!(self.call_expr());
|
||||||
Expression::Call(name, args)
|
Expression::Call(name, args)
|
||||||
},
|
}
|
||||||
__ => Expression::Variable(name)
|
__ => Expression::Variable(name),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(expr)
|
Ok(expr)
|
||||||
|
@ -11,7 +11,7 @@ pub enum Token {
|
|||||||
StrLiteral(String),
|
StrLiteral(String),
|
||||||
Identifier(String),
|
Identifier(String),
|
||||||
Operator(Op),
|
Operator(Op),
|
||||||
Keyword(Kw)
|
Keyword(Kw),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
@ -40,7 +40,7 @@ pub struct TokenizeError {
|
|||||||
|
|
||||||
impl TokenizeError {
|
impl TokenizeError {
|
||||||
fn new(msg: &str) -> TokenizeError {
|
fn new(msg: &str) -> TokenizeError {
|
||||||
TokenizeError { msg: msg.to_string() }
|
TokenizeError { msg: msg.to_string() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,15 +50,8 @@ fn is_digit(c: &char) -> bool {
|
|||||||
|
|
||||||
fn ends_identifier(c: &char) -> bool {
|
fn ends_identifier(c: &char) -> bool {
|
||||||
let c = *c;
|
let c = *c;
|
||||||
char::is_whitespace(c) ||
|
char::is_whitespace(c) || is_digit(&c) || c == ';' || c == '(' || c == ')' || c == ',' ||
|
||||||
is_digit(&c) ||
|
c == '.' || c == ',' || c == ':'
|
||||||
c == ';' ||
|
|
||||||
c == '(' ||
|
|
||||||
c == ')' ||
|
|
||||||
c == ',' ||
|
|
||||||
c == '.' ||
|
|
||||||
c == ',' ||
|
|
||||||
c == ':'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn tokenize(input: &str) -> TokenizeResult {
|
pub fn tokenize(input: &str) -> TokenizeResult {
|
||||||
@ -71,12 +64,13 @@ pub fn tokenize(input: &str) -> TokenizeResult {
|
|||||||
continue;
|
continue;
|
||||||
} else if c == '#' {
|
} else if c == '#' {
|
||||||
while let Some(c) = iter.next() {
|
while let Some(c) = iter.next() {
|
||||||
if c == '\n' { break; }
|
if c == '\n' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let cur_tok =
|
let cur_tok = if c == '\n' {
|
||||||
if c == '\n' {
|
|
||||||
Newline
|
Newline
|
||||||
} else if c == ';' {
|
} else if c == ';' {
|
||||||
Semicolon
|
Semicolon
|
||||||
@ -86,12 +80,12 @@ pub fn tokenize(input: &str) -> TokenizeResult {
|
|||||||
RParen
|
RParen
|
||||||
} else if c == ':' {
|
} else if c == ':' {
|
||||||
Colon
|
Colon
|
||||||
} else if c == ',' {
|
} else if c == ',' {
|
||||||
Comma
|
Comma
|
||||||
} else if c == '"' {
|
} else if c == '"' {
|
||||||
let mut buffer = String::with_capacity(20);
|
let mut buffer = String::with_capacity(20);
|
||||||
loop {
|
loop {
|
||||||
//TODO handle string escapes, interpolation
|
// TODO handle string escapes, interpolation
|
||||||
match iter.next() {
|
match iter.next() {
|
||||||
Some(x) if x == '"' => break,
|
Some(x) if x == '"' => break,
|
||||||
Some(x) => buffer.push(x),
|
Some(x) => buffer.push(x),
|
||||||
@ -120,14 +114,15 @@ pub fn tokenize(input: &str) -> TokenizeResult {
|
|||||||
let mut buffer = String::with_capacity(20);
|
let mut buffer = String::with_capacity(20);
|
||||||
buffer.push(c);
|
buffer.push(c);
|
||||||
loop {
|
loop {
|
||||||
if iter.peek().map_or(false, |x| !char::is_alphanumeric(*x) && !char::is_whitespace(*x)) {
|
if iter.peek().map_or(false,
|
||||||
|
|x| !char::is_alphanumeric(*x) && !char::is_whitespace(*x)) {
|
||||||
let n = iter.next().unwrap();
|
let n = iter.next().unwrap();
|
||||||
buffer.push(n);
|
buffer.push(n);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operator(Op {repr: buffer })
|
Operator(Op { repr: buffer })
|
||||||
} else {
|
} else {
|
||||||
let mut buffer = String::with_capacity(20);
|
let mut buffer = String::with_capacity(20);
|
||||||
buffer.push(c);
|
buffer.push(c);
|
||||||
@ -148,7 +143,7 @@ pub fn tokenize(input: &str) -> TokenizeResult {
|
|||||||
"let" => Keyword(Kw::Let),
|
"let" => Keyword(Kw::Let),
|
||||||
"fn" => Keyword(Kw::Fn),
|
"fn" => Keyword(Kw::Fn),
|
||||||
"null" => Keyword(Kw::Null),
|
"null" => Keyword(Kw::Null),
|
||||||
b => Identifier(b.to_string())
|
b => Identifier(b.to_string()),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -175,16 +170,17 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn tokeniziation_tests() {
|
fn tokeniziation_tests() {
|
||||||
tokentest!("let a = 3\n",
|
tokentest!("let a = 3\n",
|
||||||
"[Keyword(Let), Identifier(\"a\"), Operator(Op { repr: \"=\" }), NumLiteral(3), Newline]");
|
"[Keyword(Let), Identifier(\"a\"), Operator(Op { repr: \"=\" }), \
|
||||||
|
NumLiteral(3), Newline]");
|
||||||
|
|
||||||
tokentest!("2+1",
|
tokentest!("2+1",
|
||||||
"[NumLiteral(2), Operator(Op { repr: \"+\" }), NumLiteral(1)]");
|
"[NumLiteral(2), Operator(Op { repr: \"+\" }), NumLiteral(1)]");
|
||||||
|
|
||||||
tokentest!("2 + 1",
|
tokentest!("2 + 1",
|
||||||
"[NumLiteral(2), Operator(Op { repr: \"+\" }), NumLiteral(1)]");
|
"[NumLiteral(2), Operator(Op { repr: \"+\" }), NumLiteral(1)]");
|
||||||
|
|
||||||
tokentest!("2.3*49.2",
|
tokentest!("2.3*49.2",
|
||||||
"[NumLiteral(2.3), Operator(Op { repr: \"*\" }), NumLiteral(49.2)]");
|
"[NumLiteral(2.3), Operator(Op { repr: \"*\" }), NumLiteral(49.2)]");
|
||||||
|
|
||||||
assert!(tokenize("2.4.5").is_err());
|
assert!(tokenize("2.4.5").is_err());
|
||||||
}
|
}
|
||||||
@ -192,9 +188,9 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
#[ignore]
|
||||||
fn more_tokenization() {
|
fn more_tokenization() {
|
||||||
//it would be nice to support complicated operators in a nice, haskell-ish way
|
// it would be nice to support complicated operators in a nice, haskell-ish way
|
||||||
tokentest!("a *> b",
|
tokentest!("a *> b",
|
||||||
"[Identifier(\"a\"), Identifier(\"*>\"), Identifier(\"b\"), EOF]");
|
"[Identifier(\"a\"), Identifier(\"*>\"), Identifier(\"b\"), EOF]");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user