commit d912dc4659fd5744e26810e444d5c635d3c34f39
parent 72b3c7a9d43eadedbaf1fa0dddfc784feb034487
Author: Demonstrandum <moi@knutsen.co>
Date: Sat, 27 Jul 2019 02:36:08 +0100
Started on compiler, basic operations on constants.
Diffstat:
12 files changed, 174 insertions(+), 38 deletions(-)
diff --git a/samples/set_comp.vh b/samples/set_comp.vh
@@ -0,0 +1 @@
+n : Nat => n mod 3 is 0+
\ No newline at end of file
diff --git a/.ideas/subsets.vh b/samples/subsets.vh
diff --git a/src/bin.rs b/src/bin.rs
@@ -1,5 +1,16 @@
use valhalla;
+use std::env;
+
+fn is_vh_file(filename : &String) -> bool {
+ filename.ends_with(".vh")
+}
pub fn main() {
- valhalla::parse();
+ let args = env::args();
+
+ let files = args.filter(is_vh_file);
+
+ for file in files {
+ valhalla::parse(&file);
+ }
}
\ No newline at end of file
diff --git a/src/compiler/block.rs b/src/compiler/block.rs
@@ -0,0 +1,47 @@
+use super::super::syntax;
+use syntax::ast;
+
+use super::element;
+use super::instructions;
+
+use element::Element;
+use instructions::{Instr, Operators};
+
+#[derive(Debug)]
+pub struct LocalBlock<'a> {
+ constants : Vec<Element<'a>>,
+ locals : Vec<Element<'a>>,
+ instructions : Vec<Instr>
+}
+
+impl<'a> LocalBlock<'a> {
+ pub fn new() -> Self {
+ LocalBlock {
+ constants: vec![],
+ locals: vec![],
+ instructions: vec![]
+ }
+ }
+
+ pub fn generate(&mut self, node : ast::Nodes) {
+ match node {
+ ast::Nodes::Num(num_node) => {
+ let elem = match num_node.value {
+ ast::Numerics::Natural(n) => Element::ENatural(n),
+ ast::Numerics::Integer(n) => Element::EInteger(n),
+ ast::Numerics::Real(n) => Element::EReal(n)
+ };
+ let index = self.append_const(elem);
+ self.instructions.push(Instr::Operator(Operators::PUSH_CONST as u8));
+ self.instructions.push(Instr::Operand(index as u16))
+ },
+ _ => ()
+ };
+ }
+
+ fn append_const(&mut self, e : Element<'a>) -> usize {
+ let index = self.constants.iter().position(|c| c == &e);
+ if index.is_none() { self.constants.push(e); }
+ index.unwrap_or(self.constants.len() - 1)
+ }
+}
diff --git a/src/compiler/element.rs b/src/compiler/element.rs
@@ -0,0 +1,27 @@
+use std::fmt;
+
+pub struct Symbol<'a> {
+ hash : u32,
+ string : &'a str
+}
+
+impl<'a> fmt::Debug for Symbol<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, ":{}", self.string)
+ }
+}
+
+impl<'a> PartialEq for Symbol<'a> {
+ fn eq(&self, other : &Self) -> bool {
+ self.hash == other.hash
+ }
+}
+
+#[derive(PartialEq, Debug)]
+pub enum Element<'a> {
+ ENatural(usize),
+ EInteger(isize),
+ EReal(f64),
+ EString(String),
+ ESymbol(Symbol<'a>),
+}+
\ No newline at end of file
diff --git a/src/compiler/instructions.rs b/src/compiler/instructions.rs
@@ -0,0 +1,18 @@
+#[derive(Debug)]
+pub enum Instr {
+ Operator(u8),
+ Operand(u16)
+}
+
+#[repr(u8)]
+pub enum Operators {
+ HALT = 0,
+ PUSH_CONST = 1,
+ PUSH_LOCAL = 2,
+ PUSH_SUPER = 3,
+ POP = 4,
+ STORE_LOCAL = 5,
+ DUP = 6,
+ DUP_N = 7,
+ SWAP = 8,
+}+
\ No newline at end of file
diff --git a/src/compiler/marshal.rs b/src/compiler/marshal.rs
diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs
@@ -0,0 +1,5 @@
+//! Compilation of the syntax tree.
+mod element;
+mod instructions;
+pub mod block;
+mod marshal;+
\ No newline at end of file
diff --git a/src/lib.rs b/src/lib.rs
@@ -5,11 +5,14 @@
/// Syntax submodule, responsible for lexical analysis,
/// parsing and static analysis.
mod syntax;
+mod compiler;
-
-pub fn parse() {
- println!("\nTill Valhalla!\n");
-
- syntax::parse_file("./test.vh");
+pub fn parse(filename : &str) {
+ syntax::parse_file(filename);
+ let mut code_block = compiler::block::LocalBlock::new();
+ code_block.generate(syntax::ast::NumNode::new(3.14));
+ code_block.generate(syntax::ast::NumNode::new(34));
+ code_block.generate(syntax::ast::NumNode::new(3.14));
+ println!("Code Block:\n{:#?}", code_block)
}
diff --git a/src/syntax/mod.rs b/src/syntax/mod.rs
@@ -8,14 +8,14 @@ mod location;
mod token;
/// Abstract Syntax Tree nodes and methods.
-mod ast;
+pub mod ast;
/// Dealing with associativity and precedence.
mod operators;
/// Error messages.
#[macro_use]
-mod err;
+pub mod err;
/// Lexer splits code up into a token-stream
/// of relevant lexical tokens, making the
diff --git a/src/syntax/parser.rs b/src/syntax/parser.rs
@@ -19,7 +19,9 @@ struct ParseEnvironment<'a> {
pub root : ast::Root,
pub stream : Vec<Token>,
pub optable : operators::PrecedenceTable<'a>,
- pub file : &'a str
+ pub file : &'a str,
+
+ ignore_newline : bool
}
impl<'a> ParseEnvironment<'a> {
@@ -28,7 +30,9 @@ impl<'a> ParseEnvironment<'a> {
root: ast::Root::new(),
stream: stream,
optable: operators::PrecedenceTable::new(),
- file
+ file,
+
+ ignore_newline: false
}
}
@@ -46,6 +50,12 @@ impl<'a> ParseEnvironment<'a> {
}
}
+ fn skip_newlines(&mut self) {
+ while !self.stream.is_empty() && self.stream[0].string == "\n" {
+ self.stream.remove(0);
+ }
+ }
+
fn null_den(&mut self, token : &Token) -> Nodes {
match token.class {
TokenType::Op | TokenType::Ident => {
@@ -73,6 +83,7 @@ impl<'a> ParseEnvironment<'a> {
},
TokenType::Num => ast::NumNode::new(&*token.string),
TokenType::Str => ast::StrNode::new(&token.string),
+ TokenType::Sym => ast::SymNode::new(&token.string),
TokenType::LParen => {
let current = self.stream.get(0);
if current.is_none() || current.unwrap().class == TokenType::EOF {
@@ -81,7 +92,13 @@ impl<'a> ParseEnvironment<'a> {
self.stream.remove(0);
return ast::EmptyNode::new();
}
+
+
+ self.ignore_newline = true;
+ self.skip_newlines();
let expr = self.expr(0);
+ self.skip_newlines();
+ self.ignore_newline = false;
self.expect(TokenType::RParen, self.stream.get(0));
self.stream.remove(0);
expr
@@ -92,9 +109,13 @@ impl<'a> ParseEnvironment<'a> {
}
fn expr(&mut self, right_prec : i32) -> Nodes {
- let popped = &self.stream.remove(0);
- let mut left = self.null_den(popped);
+ let mut popped = self.stream.remove(0);
+ while !self.stream.is_empty() && self.ignore_newline && popped.string == "\n" {
+ popped = self.stream.remove(0);
+ }
+ let mut left = self.null_den(&popped);
+ if self.ignore_newline { self.skip_newlines(); }
if self.stream.is_empty()
|| self.stream[0].class == TokenType::EOF
|| self.stream[0].class == TokenType::Term
@@ -104,6 +125,10 @@ impl<'a> ParseEnvironment<'a> {
while self.optable.precedence(&self.stream[0].string).unwrap_or(190) > right_prec {
let next = &(&self.stream[0].string).clone();
+ if self.ignore_newline && next == "\n" {
+ self.stream.remove(0);
+ continue;
+ }
if next == "\0" || next == "\n" || next == ")" { break; }
let maybe_op = self.optable.lookup(next, 2);
@@ -112,36 +137,34 @@ impl<'a> ParseEnvironment<'a> {
let cloned = operators::Operator::new(next, op.precedence, op.associativity, 2);
left = self.left_den(left, cloned);
} else { // Function call.
- let mut pushed = false;
- match left {
- Nodes::Call(ref mut call) => {
- if call.operands.is_empty() {
- call.operands.push(self.expr(190));
- pushed = true;
- }
- }
- _ => ()
- };
- if !pushed {
- left = self.func_appl(left);
- }
+ left = self.func_apply(left);
}
}
return left;
}
- fn func_appl(&mut self, left : Nodes) -> Nodes {
- println!("Creating function call with:\n --> {}", left);
+ fn func_apply(&mut self, mut left : Nodes) -> Nodes {
+ let mut pushed = false;
+ match left {
+ Nodes::Call(ref mut call) => {
+ if call.operands.is_empty() {
+ call.operands.push(self.expr(190));
+ pushed = true;
+ }
+ },
+ _ => ()
+ };
+ if pushed { return left; }
ast::CallNode::new(left, vec![self.expr(190)])
}
fn left_den(&mut self, left : Nodes, op : operators::Operator) -> Nodes {
- let first_appl = ast::CallNode::new(ast::IdentNode::new(op.name), vec![left]);
+ let first_apply = ast::CallNode::new(ast::IdentNode::new(op.name), vec![left]);
if self.stream[0].class == TokenType::RParen {
- return first_appl;
+ return first_apply;
}
let right = self.expr(op.precedence - (if op.is_right() { 1 } else { 0 }));
- ast::CallNode::new(first_appl, vec![right])
+ ast::CallNode::new(first_apply, vec![right])
}
fn expect(&self, tt : TokenType, maybe_t : Option<&Token>) {
diff --git a/test.vh b/test.vh
@@ -1,7 +1,4 @@
-2 + 3
--- same as
-(+) 2 3
--- same as
-(2 +) 3
--- same as
-(+ 3) 2-
\ No newline at end of file
+2
+34
+2.3
+-2+
\ No newline at end of file