Compare commits
No commits in common. "33162fda6e581ba67d2f4baca9426b9919bda64b" and "9c9a4cab1c2cb3e5bf84de2570f8110f7cd74a25" have entirely different histories.
33162fda6e
...
9c9a4cab1c
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1 @@
|
||||||
/target
|
/target
|
||||||
Cargo.lock
|
|
||||||
|
|
92
Cargo.lock
generated
Normal file
92
Cargo.lock
generated
Normal file
|
@ -0,0 +1,92 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.147"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "plonkus"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"socket2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_gnullvm",
|
||||||
|
"windows_aarch64_msvc",
|
||||||
|
"windows_i686_gnu",
|
||||||
|
"windows_i686_msvc",
|
||||||
|
"windows_x86_64_gnu",
|
||||||
|
"windows_x86_64_gnullvm",
|
||||||
|
"windows_x86_64_msvc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.48.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|
@ -6,4 +6,4 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "0.8.5"
|
socket2 = "0.5.3"
|
||||||
|
|
11
src/assembly.rs
Normal file
11
src/assembly.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
use crate::tokeniser::Token;
|
||||||
|
|
||||||
|
pub fn assemblize(tokens: Vec<Token>) -> String {
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
|
for token in tokens {
|
||||||
|
output += "hii"
|
||||||
|
}
|
||||||
|
|
||||||
|
output
|
||||||
|
}
|
357
src/ast.rs
357
src/ast.rs
|
@ -1,357 +0,0 @@
|
||||||
extern crate rand;
|
|
||||||
|
|
||||||
use rand::{distributions::Alphanumeric, Rng};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct Function {
|
|
||||||
pub name: String,
|
|
||||||
pub statements: Vec<Statement>,
|
|
||||||
assembly: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Statement {
|
|
||||||
FunctionCall(String, Vec<ValueNode>),
|
|
||||||
VariableDeclaration(String, ValueNode),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum ValueNode {
|
|
||||||
Literal(Literal),
|
|
||||||
Operator(Operator),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Literal {
|
|
||||||
Int(i64),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub enum Operator {
|
|
||||||
Add(Box<ValueNode>, Box<ValueNode>),
|
|
||||||
Sub(Box<ValueNode>, Box<ValueNode>),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct AssemblerState {
|
|
||||||
pub functions: HashMap<String, Function>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait Node {
|
|
||||||
fn to_assembly(&self, state: &mut AssemblerState) -> String;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Function {
|
|
||||||
pub fn new(name: String, statements: Vec<Statement>) -> Function {
|
|
||||||
Function {
|
|
||||||
name,
|
|
||||||
statements,
|
|
||||||
assembly: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&self, state: &mut AssemblerState) -> Function {
|
|
||||||
state.functions.insert(self.name.clone(), self.to_owned());
|
|
||||||
self.to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AssemblerState {
|
|
||||||
pub fn new() -> AssemblerState {
|
|
||||||
AssemblerState {
|
|
||||||
functions: get_default_functions(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_default_functions() -> HashMap<String, Function> {
|
|
||||||
let mut functions = HashMap::new();
|
|
||||||
functions.insert(
|
|
||||||
"out".to_string(),
|
|
||||||
Function {
|
|
||||||
name: "exit".to_string(),
|
|
||||||
statements: vec![],
|
|
||||||
assembly: Some(
|
|
||||||
"
|
|
||||||
out:
|
|
||||||
;
|
|
||||||
; Pop the argument of the stack
|
|
||||||
;
|
|
||||||
|
|
||||||
SE-OUT RAM-ADDR-U-IN 0xFF ; Set ram address to stack end
|
|
||||||
RAM-OUT OUTPUT-IN 0xFF ; Output top address onto output register
|
|
||||||
|
|
||||||
ROM-OUT FLAGS-IN 0x80 ; Subtract mode
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Subtract one
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store in SE
|
|
||||||
ROM-OUT FLAGS-IN 0x00 ; Add mode
|
|
||||||
|
|
||||||
;
|
|
||||||
; Pop the return address of the stack
|
|
||||||
;
|
|
||||||
|
|
||||||
SE-OUT RAM-ADDR-U-IN 0xFF ; Set ram address to stack end
|
|
||||||
RAM-OUT ROM-ADDR-U-IN 0xFF ; Store top address in ROM jump address
|
|
||||||
|
|
||||||
ROM-OUT FLAGS-IN 0x80 ; Subtract mode
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Subtract one
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store in SE
|
|
||||||
ROM-OUT FLAGS-IN 0x00 ; Add mode
|
|
||||||
|
|
||||||
F-OUT JMP 0xFF"
|
|
||||||
.to_string(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
functions.insert(
|
|
||||||
"exit".to_string(),
|
|
||||||
Function {
|
|
||||||
name: "exit".to_string(),
|
|
||||||
statements: vec![],
|
|
||||||
assembly: Some(
|
|
||||||
"
|
|
||||||
exit:
|
|
||||||
F-OUT JMP 0xFF"
|
|
||||||
.to_string(),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
functions
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for Function {
|
|
||||||
fn to_assembly(&self, state: &mut AssemblerState) -> String {
|
|
||||||
match &self.assembly {
|
|
||||||
Some(v) => v.to_string(),
|
|
||||||
None => format!(
|
|
||||||
"{}:\n{}
|
|
||||||
;
|
|
||||||
; Pop the return address of the stack
|
|
||||||
;
|
|
||||||
|
|
||||||
SE-OUT RAM-ADDR-U-IN 0xFF ; Set ram address to stack end
|
|
||||||
RAM-OUT ROM-ADDR-U-IN 0xFF ; Store top address in ROM jump address
|
|
||||||
|
|
||||||
ROM-OUT FLAGS-IN 0x80 ; Subtract mode
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Subtract one
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store in SE
|
|
||||||
ROM-OUT FLAGS-IN 0x00 ; Add mode
|
|
||||||
|
|
||||||
F-OUT JMP 0xFF
|
|
||||||
",
|
|
||||||
self.name,
|
|
||||||
{
|
|
||||||
self.statements
|
|
||||||
.iter()
|
|
||||||
.map(|x| x.to_assembly(state))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join("\n")
|
|
||||||
}
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for Statement {
|
|
||||||
fn to_assembly(&self, state: &mut AssemblerState) -> String {
|
|
||||||
match self {
|
|
||||||
Statement::FunctionCall(name, arguments) => {
|
|
||||||
if !state.functions.contains_key(name) {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
let argument_assembly: String = arguments
|
|
||||||
.into_iter()
|
|
||||||
.map(|x| x.to_assembly(state))
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join("\n");
|
|
||||||
|
|
||||||
let call_id: String = rand::thread_rng()
|
|
||||||
.sample_iter(&Alphanumeric)
|
|
||||||
.take(30)
|
|
||||||
.map(char::from)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
format!(
|
|
||||||
"
|
|
||||||
;
|
|
||||||
; Stack
|
|
||||||
;
|
|
||||||
|
|
||||||
; Increment Stack Pointer
|
|
||||||
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Add 1
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store
|
|
||||||
|
|
||||||
; Store in top stack pointer
|
|
||||||
|
|
||||||
ALU-OUT RAM-ADDR-U-IN 0xFF ; Store in RAM address
|
|
||||||
ROM-OUT RAM-IN ${name}-{call_id} ; Store address after jump in ram
|
|
||||||
|
|
||||||
;
|
|
||||||
; Arguments
|
|
||||||
;
|
|
||||||
|
|
||||||
{argument_assembly}
|
|
||||||
|
|
||||||
;
|
|
||||||
; Jump
|
|
||||||
;
|
|
||||||
ROM-OUT ROM-ADDR-U-IN ${name} ; Jump to function label
|
|
||||||
F-OUT JMP 0xFF ; Jump to function
|
|
||||||
|
|
||||||
{name}-{call_id}:
|
|
||||||
"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Statement::VariableDeclaration(_name, _value) => {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for ValueNode {
|
|
||||||
fn to_assembly(&self, state: &mut AssemblerState) -> String {
|
|
||||||
match self {
|
|
||||||
ValueNode::Literal(v) => v.to_assembly(state),
|
|
||||||
ValueNode::Operator(o) => o.to_assembly(state),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for Literal {
|
|
||||||
fn to_assembly(&self, _state: &mut AssemblerState) -> String {
|
|
||||||
match self {
|
|
||||||
Literal::Int(v) => {
|
|
||||||
format!(
|
|
||||||
"
|
|
||||||
;
|
|
||||||
; Stack
|
|
||||||
;
|
|
||||||
|
|
||||||
; Increment Stack Pointer
|
|
||||||
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Add 1
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store
|
|
||||||
|
|
||||||
; Store in top stack pointer
|
|
||||||
|
|
||||||
ALU-OUT RAM-ADDR-U-IN 0xFF ; Store in RAM address
|
|
||||||
ROM-OUT RAM-IN {v}; Store literal value in RAM"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Node for Operator {
|
|
||||||
fn to_assembly(&self, state: &mut AssemblerState) -> String {
|
|
||||||
match self {
|
|
||||||
Operator::Add(a, b) => {
|
|
||||||
format!(
|
|
||||||
"
|
|
||||||
{}
|
|
||||||
{}
|
|
||||||
|
|
||||||
SE-OUT RAM-ADDR-U-IN 0xFF ; Set ram address to stack end
|
|
||||||
RAM-OUT C-IN 0xFF ; Output top address onto output register
|
|
||||||
|
|
||||||
ROM-OUT FLAGS-IN 0x80 ; Subtract mode
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Subtract one
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store in SE
|
|
||||||
|
|
||||||
SE-OUT RAM-ADDR-U-IN 0xFF ; Set ram address to stack end
|
|
||||||
RAM-OUT D-IN 0xFF ; Output top address onto output register
|
|
||||||
|
|
||||||
ROM-OUT FLAGS-IN 0x80 ; Subtract mode
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Subtract one
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store in SE
|
|
||||||
ROM-OUT FLAGS-IN 0x00 ; Add mode
|
|
||||||
|
|
||||||
C-OUT A-IN 0xFF ; Move temporary values into a register for alu computation
|
|
||||||
D-OUT B-IN 0xFF ; Move temporary values into a register for alu computation
|
|
||||||
ALU-OUT C-IN 0xFF ; Move ALU output into temporary register
|
|
||||||
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Add 1
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store
|
|
||||||
|
|
||||||
ALU-OUT RAM-ADDR-U-IN 0xFF ; Store in RAM address
|
|
||||||
C-OUT RAM-IN 0xFF ; Store address after jump in ram
|
|
||||||
",
|
|
||||||
a.to_assembly(state),
|
|
||||||
b.to_assembly(state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Operator::Sub(a, b) => {
|
|
||||||
format!(
|
|
||||||
"
|
|
||||||
{}
|
|
||||||
{}
|
|
||||||
|
|
||||||
SE-OUT RAM-ADDR-U-IN 0xFF ; Set ram address to stack end
|
|
||||||
RAM-OUT C-IN 0xFF ; Output top address onto output register
|
|
||||||
|
|
||||||
ROM-OUT FLAGS-IN 0x80 ; Subtract mode
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Subtract one
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store in SE
|
|
||||||
|
|
||||||
SE-OUT RAM-ADDR-U-IN 0xFF ; Set ram address to stack end
|
|
||||||
RAM-OUT D-IN 0xFF ; Output top address onto output register
|
|
||||||
|
|
||||||
ROM-OUT FLAGS-IN 0x80 ; Subtract mode
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Subtract one
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store in SE
|
|
||||||
ROM-OUT FLAGS-IN 0x00 ; Add mode
|
|
||||||
|
|
||||||
ROM-OUT FLAGS-IN 0x80 ; Subtract mode
|
|
||||||
C-OUT B-IN 0xFF ; Move temporary values into a register for alu computation
|
|
||||||
D-OUT A-IN 0xFF ; Move temporary values into a register for alu computation
|
|
||||||
ALU-OUT C-IN 0xFF ; Move ALU output into temporary register
|
|
||||||
ROM-OUT FLAGS-IN 0x00 ; Add mode
|
|
||||||
|
|
||||||
SE-OUT A-IN 0xFF ; Fetch SE
|
|
||||||
ROM-OUT B-IN 0x01 ; Add 1
|
|
||||||
ALU-OUT SE-IN 0xFF ; Store
|
|
||||||
|
|
||||||
ALU-OUT RAM-ADDR-U-IN 0xFF ; Store in RAM address
|
|
||||||
C-OUT RAM-IN 0xFF ; Store address after jump in ram
|
|
||||||
",
|
|
||||||
a.to_assembly(state),
|
|
||||||
b.to_assembly(state)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_assembly(functions: Vec<Function>) -> String {
|
|
||||||
let mut final_product: String = "".to_owned();
|
|
||||||
let mut std_function_assembly = "".to_owned();
|
|
||||||
let mut state = AssemblerState::new();
|
|
||||||
|
|
||||||
for std_function in state.clone().functions {
|
|
||||||
std_function_assembly += &std_function.1.to_assembly(&mut state);
|
|
||||||
}
|
|
||||||
|
|
||||||
for standard_function in &functions {
|
|
||||||
standard_function.add(&mut state);
|
|
||||||
}
|
|
||||||
|
|
||||||
for standard_function in &functions {
|
|
||||||
final_product += &standard_function.to_assembly(&mut state);
|
|
||||||
}
|
|
||||||
|
|
||||||
final_product + &std_function_assembly
|
|
||||||
}
|
|
17
src/main.rs
17
src/main.rs
|
@ -1,17 +1,12 @@
|
||||||
mod ast;
|
mod assembly;
|
||||||
mod parse;
|
|
||||||
mod tokeniser;
|
mod tokeniser;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let filename = "test.plonkus";
|
let filename = std::env::args().nth(1).expect("No filename argument");
|
||||||
|
let contents =
|
||||||
|
std::fs::read_to_string(&filename).expect(&format!("No file named {}", &filename));
|
||||||
|
|
||||||
let contents = std::fs::read_to_string(filename).expect(&format!("No file named {}", filename));
|
let tokens = dbg!(tokeniser::tokenise(contents));
|
||||||
|
|
||||||
let tokens = tokeniser::tokenise(contents);
|
let assembled = dbg!(assembly::assemblize(tokens));
|
||||||
|
|
||||||
let functions = parse::ast(tokens);
|
|
||||||
|
|
||||||
let assembly = ast::to_assembly(functions);
|
|
||||||
|
|
||||||
println!("{}", assembly);
|
|
||||||
}
|
}
|
||||||
|
|
199
src/parse.rs
199
src/parse.rs
|
@ -1,199 +0,0 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
|
||||||
|
|
||||||
use crate::ast::*;
|
|
||||||
use crate::tokeniser::Keyword;
|
|
||||||
use crate::tokeniser::Token;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
enum ParseState {
|
|
||||||
Function(Function),
|
|
||||||
Statement(Function),
|
|
||||||
None(Vec<Function>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Function {
|
|
||||||
fn push_statement(&mut self, statement: Statement) -> Function {
|
|
||||||
self.statements.push(statement);
|
|
||||||
self.to_owned()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_math(tokens: &Vec<Token>) -> ValueNode {
|
|
||||||
let mut prioritizing_order: HashMap<i64, HashSet<Token>> = HashMap::new();
|
|
||||||
prioritizing_order.insert(0, HashSet::from([Token::Plus, Token::Minus]));
|
|
||||||
|
|
||||||
let mut ordered_binops: Vec<Token> = Vec::new();
|
|
||||||
let mut ordered_binops_indexes: Vec<usize> = Vec::new();
|
|
||||||
|
|
||||||
if tokens.len() == 1 {
|
|
||||||
return match &tokens[0] {
|
|
||||||
Token::Number(n) => ValueNode::Literal(Literal::Int(n.parse::<i64>().unwrap())),
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for j in prioritizing_order.keys() {
|
|
||||||
let mut i = 0;
|
|
||||||
let current_order_binops = prioritizing_order.get(j).unwrap();
|
|
||||||
|
|
||||||
while i < tokens.len() {
|
|
||||||
for binop in current_order_binops {
|
|
||||||
if &tokens[i] == binop {
|
|
||||||
ordered_binops.push(binop.to_owned());
|
|
||||||
ordered_binops_indexes.push(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let binop = ordered_binops.pop().unwrap();
|
|
||||||
let binop_index = ordered_binops_indexes.pop().unwrap();
|
|
||||||
|
|
||||||
let mut a: Vec<Token> = Vec::new();
|
|
||||||
let mut b: Vec<Token> = Vec::new();
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
while i < tokens.len() {
|
|
||||||
if i < binop_index {
|
|
||||||
a.push(tokens[i].clone());
|
|
||||||
}
|
|
||||||
if i > binop_index {
|
|
||||||
b.push(tokens[i].clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return match binop {
|
|
||||||
Token::Plus => ValueNode::Operator(Operator::Add(
|
|
||||||
Box::new(parse_math(&a)),
|
|
||||||
Box::new(parse_math(&b)),
|
|
||||||
)),
|
|
||||||
Token::Minus => ValueNode::Operator(Operator::Sub(
|
|
||||||
Box::new(parse_math(&a)),
|
|
||||||
Box::new(parse_math(&b)),
|
|
||||||
)),
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_statement(
|
|
||||||
parse_state: &mut ParseState,
|
|
||||||
i: &mut usize,
|
|
||||||
tokens: &Vec<Token>,
|
|
||||||
functions: &Vec<Function>,
|
|
||||||
) -> ParseState {
|
|
||||||
let mut current_function = match parse_state {
|
|
||||||
ParseState::Statement(f) => f.to_owned(),
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if tokens[i.to_owned()] == Token::CloseSquiglyBracket {
|
|
||||||
let mut functions = functions.to_owned();
|
|
||||||
functions.push(current_function);
|
|
||||||
|
|
||||||
return ParseState::None(functions);
|
|
||||||
}
|
|
||||||
|
|
||||||
let statement = match &tokens[i.to_owned()] {
|
|
||||||
Token::Keyword(Keyword::Let) => {
|
|
||||||
*i += 1;
|
|
||||||
let name = match tokens[*i].clone() {
|
|
||||||
Token::Identifier(identifier) => identifier,
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
*i += 1;
|
|
||||||
match tokens[*i].clone() {
|
|
||||||
Token::Equals => {}
|
|
||||||
_ => todo!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut declaration_tokens: Vec<Token> = Vec::new();
|
|
||||||
while tokens[*i] != Token::Semi {
|
|
||||||
*i += 1;
|
|
||||||
declaration_tokens.push(tokens[*i].clone());
|
|
||||||
}
|
|
||||||
Statement::VariableDeclaration(name, parse_math(&declaration_tokens))
|
|
||||||
}
|
|
||||||
Token::Identifier(identifier) => {
|
|
||||||
*i += 1;
|
|
||||||
|
|
||||||
let mut declaration_tokens: Vec<Vec<Token>> = Vec::new();
|
|
||||||
|
|
||||||
*i += 1;
|
|
||||||
while tokens[*i] != Token::CloseParanthesis {
|
|
||||||
let mut argument_tokens: Vec<Token> = Vec::new();
|
|
||||||
while tokens[*i] != Token::Comma {
|
|
||||||
argument_tokens.push(tokens[*i].clone());
|
|
||||||
*i += 1;
|
|
||||||
}
|
|
||||||
declaration_tokens.push(argument_tokens);
|
|
||||||
*i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*i += 1;
|
|
||||||
|
|
||||||
let mut arguments: Vec<ValueNode> = Vec::new();
|
|
||||||
|
|
||||||
for token_vec in &declaration_tokens {
|
|
||||||
if token_vec == &Vec::new() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
arguments.push(parse_math(token_vec));
|
|
||||||
}
|
|
||||||
|
|
||||||
Statement::FunctionCall(identifier.to_owned(), arguments)
|
|
||||||
}
|
|
||||||
_other => {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
current_function.push_statement(statement);
|
|
||||||
|
|
||||||
return ParseState::Statement(current_function);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ast(tokens: Vec<Token>) -> Vec<Function> {
|
|
||||||
let mut parse_state = ParseState::None(Vec::new());
|
|
||||||
let mut functions: Vec<Function> = Vec::new();
|
|
||||||
|
|
||||||
let mut i = 0;
|
|
||||||
while i < tokens.len() {
|
|
||||||
parse_state = match &parse_state {
|
|
||||||
ParseState::None(funcs) => {
|
|
||||||
functions = funcs.to_owned();
|
|
||||||
// Expect function and shit
|
|
||||||
match &tokens[i] {
|
|
||||||
Token::Keyword(keyword) => match keyword {
|
|
||||||
Keyword::Function => {
|
|
||||||
ParseState::Function(Function::new("".to_string(), Vec::new()))
|
|
||||||
}
|
|
||||||
_ => todo!(),
|
|
||||||
},
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ParseState::Function(func) => match &tokens[i] {
|
|
||||||
Token::Identifier(identifier) => {
|
|
||||||
ParseState::Function(Function::new(identifier.to_owned(), Vec::new()))
|
|
||||||
}
|
|
||||||
Token::OpenSquiglyBracket => ParseState::Statement(func.to_owned()),
|
|
||||||
_ => todo!(),
|
|
||||||
},
|
|
||||||
ParseState::Statement(_function) => {
|
|
||||||
parse_statement(&mut parse_state, &mut i, &tokens, &functions)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
match parse_state {
|
|
||||||
ParseState::None(v) => v,
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +1,19 @@
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Token {
|
pub enum Token {
|
||||||
Semi,
|
SEMI,
|
||||||
Equals,
|
NUMBER(String),
|
||||||
Comma,
|
IDENTIFIER(String),
|
||||||
Plus,
|
KEYWORD(Keyword),
|
||||||
Minus,
|
|
||||||
Number(String),
|
|
||||||
Identifier(String),
|
|
||||||
Keyword(Keyword),
|
|
||||||
OpenParanthesis,
|
|
||||||
CloseParanthesis,
|
|
||||||
OpenSquiglyBracket,
|
|
||||||
CloseSquiglyBracket,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Keyword {
|
pub enum Keyword {
|
||||||
Return,
|
RETURN,
|
||||||
Function,
|
|
||||||
Let,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TokenFinishedUnfinished {
|
enum TokenFinishedUnfinished {
|
||||||
Unfinished(Option<Token>),
|
UNFINISHED(Option<Token>),
|
||||||
Finished(Token),
|
FINISHED(Token),
|
||||||
}
|
}
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -34,9 +24,7 @@ fn generate_keyword_map() -> HashMap<String, Keyword> {
|
||||||
let mut keywords: HashMap<String, Keyword> = HashMap::new();
|
let mut keywords: HashMap<String, Keyword> = HashMap::new();
|
||||||
|
|
||||||
use Keyword as K;
|
use Keyword as K;
|
||||||
keywords.insert("return".to_string(), K::Return);
|
keywords.insert("return".to_string(), K::RETURN);
|
||||||
keywords.insert("fn".to_string(), K::Function);
|
|
||||||
keywords.insert("let".to_string(), K::Let);
|
|
||||||
|
|
||||||
keywords
|
keywords
|
||||||
}
|
}
|
||||||
|
@ -48,75 +36,46 @@ fn tokenise_current_character(
|
||||||
let keywords = generate_keyword_map();
|
let keywords = generate_keyword_map();
|
||||||
|
|
||||||
match current_token_type {
|
match current_token_type {
|
||||||
Some(Token::Number(ref v)) => {
|
Some(Token::NUMBER(ref v)) => {
|
||||||
let mut current_characters = v.clone();
|
let mut current_characters = v.clone();
|
||||||
|
|
||||||
if current_character.is_digit(10) {
|
if current_character.is_digit(10) {
|
||||||
current_characters.push(current_character);
|
current_characters.push(current_character);
|
||||||
return Unfinished(Some(Token::Number(current_characters)));
|
return UNFINISHED(Some(Token::NUMBER(current_characters)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Finished(Token::Number(current_characters))
|
FINISHED(Token::NUMBER(current_characters))
|
||||||
}
|
}
|
||||||
Some(Token::Identifier(ref v)) => {
|
Some(Token::IDENTIFIER(ref v)) => {
|
||||||
let mut current_characters = v.clone();
|
let mut current_characters = v.clone();
|
||||||
|
|
||||||
if current_character.is_alphanumeric() {
|
if current_character.is_alphanumeric() {
|
||||||
current_characters.push(current_character);
|
current_characters.push(current_character);
|
||||||
return Unfinished(Some(Token::Identifier(current_characters)));
|
return UNFINISHED(Some(Token::IDENTIFIER(current_characters)));
|
||||||
}
|
}
|
||||||
|
|
||||||
match keywords.get(¤t_characters) {
|
match keywords.get(¤t_characters) {
|
||||||
Some(keyword) => Finished(Token::Keyword(keyword.clone())),
|
Some(keyword) => FINISHED(Token::KEYWORD(keyword.clone())),
|
||||||
None => Finished(Token::Identifier(current_characters)),
|
None => FINISHED(Token::IDENTIFIER(current_characters)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Some(Token::SEMI) => FINISHED(Token::SEMI), // Needed because we're always going back a step after returning finished token
|
||||||
None => {
|
None => {
|
||||||
if current_character.is_digit(10) {
|
if current_character.is_digit(10) {
|
||||||
return Unfinished(Some(Token::Number(String::from(current_character))));
|
return UNFINISHED(Some(Token::NUMBER(String::from(current_character))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if current_character.is_alphabetic() {
|
if current_character.is_alphabetic() {
|
||||||
return Unfinished(Some(Token::Identifier(String::from(current_character))));
|
return UNFINISHED(Some(Token::IDENTIFIER(String::from(current_character))));
|
||||||
}
|
}
|
||||||
|
|
||||||
if current_character == ';' {
|
if current_character == ';' {
|
||||||
return Unfinished(Some(Token::Semi));
|
return UNFINISHED(Some(Token::SEMI));
|
||||||
}
|
}
|
||||||
|
|
||||||
if current_character == '(' {
|
UNFINISHED(None)
|
||||||
return Unfinished(Some(Token::OpenParanthesis));
|
|
||||||
}
|
|
||||||
if current_character == ')' {
|
|
||||||
return Unfinished(Some(Token::CloseParanthesis));
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_character == '{' {
|
|
||||||
return Unfinished(Some(Token::OpenSquiglyBracket));
|
|
||||||
}
|
|
||||||
if current_character == '}' {
|
|
||||||
return Unfinished(Some(Token::CloseSquiglyBracket));
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_character == '=' {
|
|
||||||
return Unfinished(Some(Token::Equals));
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_character == ',' {
|
|
||||||
return Unfinished(Some(Token::Comma));
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_character == '+' {
|
|
||||||
return Unfinished(Some(Token::Plus));
|
|
||||||
}
|
|
||||||
|
|
||||||
if current_character == '-' {
|
|
||||||
return Unfinished(Some(Token::Minus));
|
|
||||||
}
|
|
||||||
|
|
||||||
Unfinished(None)
|
|
||||||
}
|
}
|
||||||
Some(v) => Finished(v),
|
Some(v) => FINISHED(v),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,10 +90,10 @@ pub fn tokenise(input: String) -> Vec<Token> {
|
||||||
current_character = input.as_bytes()[i] as char;
|
current_character = input.as_bytes()[i] as char;
|
||||||
|
|
||||||
match tokenise_current_character(current_character, current_token_type.clone()) {
|
match tokenise_current_character(current_character, current_token_type.clone()) {
|
||||||
Unfinished(v) => {
|
UNFINISHED(v) => {
|
||||||
current_token_type = v.clone();
|
current_token_type = v.clone();
|
||||||
}
|
}
|
||||||
Finished(v) => {
|
FINISHED(v) => {
|
||||||
tokens.push(v);
|
tokens.push(v);
|
||||||
current_token_type = None;
|
current_token_type = None;
|
||||||
i -= 1;
|
i -= 1;
|
||||||
|
|
|
@ -1,4 +1 @@
|
||||||
fn main {
|
return 42;
|
||||||
out(42 - 3 - 1,);
|
|
||||||
exit(,);
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue