WIP syscalls
This commit is contained in:
107
src/compiler/mod.rs
Normal file
107
src/compiler/mod.rs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::parser::tree_node::*;
|
||||||
|
use crate::parser::Parser as ASTParser;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// Represents the return keyword. Used as a variable name for the register.
|
||||||
|
const RETURN: &'static str = "ret";
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum CompileError {
|
||||||
|
#[error(transparent)]
|
||||||
|
ParseError(#[from] crate::parser::ParseError),
|
||||||
|
#[error("A fatal error has occurred with the compiler. Scope could not be found.")]
|
||||||
|
ScopeError,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Compiler {
|
||||||
|
parser: ASTParser,
|
||||||
|
/// Max stack size for the program is by default 512.
|
||||||
|
variable_scope: Vec<HashMap<String, usize>>,
|
||||||
|
function_scope: Vec<HashMap<String, usize>>,
|
||||||
|
output: String,
|
||||||
|
stack_pointer: usize,
|
||||||
|
/// A map of variable names to register numbers. 0-15 are reserved for variables, 16 is the stack pointer, 17 is the return address
|
||||||
|
register: HashMap<String, u8>,
|
||||||
|
max_stack_size: usize,
|
||||||
|
current_line: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Compiler {
|
||||||
|
pub fn new(parser: ASTParser, max_stack_size: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
parser,
|
||||||
|
variable_scope: Vec::new(),
|
||||||
|
function_scope: Vec::new(),
|
||||||
|
output: String::new(),
|
||||||
|
stack_pointer: 0,
|
||||||
|
register: HashMap::new(),
|
||||||
|
max_stack_size,
|
||||||
|
current_line: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile(mut self) -> Result<String, CompileError> {
|
||||||
|
let ast = self.parser.parse_all()?;
|
||||||
|
|
||||||
|
let Some(ast) = ast else {
|
||||||
|
return Ok(String::new());
|
||||||
|
};
|
||||||
|
|
||||||
|
self.expression(ast)?;
|
||||||
|
|
||||||
|
Ok(self.output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expression(&mut self, expression: Expression) -> Result<(), CompileError> {
|
||||||
|
match expression {
|
||||||
|
Expression::BlockExpression(block) => self.block_expression(block)?,
|
||||||
|
Expression::DeclarationExpression(name, expr) => {
|
||||||
|
self.declaration_expression(name, expr)?
|
||||||
|
}
|
||||||
|
Expression::ReturnExpression(expr) => self.return_expression(*expr)?,
|
||||||
|
_ => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn return_expression(&mut self, expression: Expression) -> Result<(), CompileError> {
|
||||||
|
// pop last var off the stack and push it into the first available register
|
||||||
|
let register = self.register.len() as u8;
|
||||||
|
self.output.push_str(&format!("pop r{}\n", register));
|
||||||
|
self.stack_pointer
|
||||||
|
.checked_sub(1)
|
||||||
|
.ok_or(CompileError::ScopeError)?;
|
||||||
|
self.current_line += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn declaration_expression(
|
||||||
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
expression: Box<Expression>,
|
||||||
|
) -> Result<(), CompileError> {
|
||||||
|
self.expression(*expression)?;
|
||||||
|
self.variable_scope
|
||||||
|
.last_mut()
|
||||||
|
.ok_or(CompileError::ScopeError)?
|
||||||
|
.insert(name, self.stack_pointer);
|
||||||
|
self.stack_pointer += 1;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn block_expression(&mut self, expression: BlockExpression) -> Result<(), CompileError> {
|
||||||
|
// Push a new scope. This will be read from all the child expressions
|
||||||
|
self.variable_scope.push(HashMap::new());
|
||||||
|
|
||||||
|
for expr in expression.0 {
|
||||||
|
self.expression(expr)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the scope we just added, all variables are now out of scope
|
||||||
|
self.variable_scope.pop();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/main.rs
10
src/main.rs
@@ -1,5 +1,6 @@
|
|||||||
#![feature(error_generic_member_access)]
|
#![feature(error_generic_member_access)]
|
||||||
|
|
||||||
|
mod compiler;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod tokenizer;
|
mod tokenizer;
|
||||||
|
|
||||||
@@ -15,6 +16,8 @@ enum StationlangError {
|
|||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ParserError(#[from] parser::ParseError),
|
ParserError(#[from] parser::ParseError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
CompileError(#[from] compiler::CompileError),
|
||||||
|
#[error(transparent)]
|
||||||
IoError(#[from] std::io::Error),
|
IoError(#[from] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,11 +57,10 @@ fn run_logic() -> Result<(), StationlangError> {
|
|||||||
|
|
||||||
let mut parser = ASTParser::new(tokenizer);
|
let mut parser = ASTParser::new(tokenizer);
|
||||||
|
|
||||||
let ast = parser.parse_all()?;
|
let compiler = compiler::Compiler::new(parser, args.stack_size);
|
||||||
|
|
||||||
if let Some(ast) = ast {
|
let output = compiler.compile()?;
|
||||||
println!("{}", ast);
|
println!("{}", output);
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
mod tree_node;
|
pub mod tree_node;
|
||||||
|
pub mod sys_call;
|
||||||
|
|
||||||
use crate::tokenizer::{
|
use crate::tokenizer::{
|
||||||
token::{Keyword, Symbol, Token, TokenType},
|
token::{Keyword, Symbol, Token, TokenType},
|
||||||
|
|||||||
125
src/parser/sys_call.rs
Normal file
125
src/parser/sys_call.rs
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
use super::{Literal, LiteralOrVariable};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum Math {
|
||||||
|
/// Gets the absolute value of a number.
|
||||||
|
/// ## In Game
|
||||||
|
/// `abs r? a(r?|num)`
|
||||||
|
Abs(LiteralOrVariable),
|
||||||
|
/// Rounds a number up to the nearest whole number.
|
||||||
|
/// ## In Game
|
||||||
|
/// `ceil r? a(r?|num)`
|
||||||
|
Ceil(LiteralOrVariable),
|
||||||
|
/// Rounds a number down to the nearest whole number.
|
||||||
|
/// ## In Game
|
||||||
|
/// `floor r? a(r?|num)`
|
||||||
|
Floor(LiteralOrVariable),
|
||||||
|
/// Computes the natural logarithm of a number.
|
||||||
|
/// ## In Game
|
||||||
|
/// `log r? a(r?|num)`
|
||||||
|
Log(LiteralOrVariable),
|
||||||
|
/// Computes the maximum of two numbers.
|
||||||
|
/// ## In Game
|
||||||
|
/// `max r? a(r?|num) b(r?|num)`
|
||||||
|
Max(LiteralOrVariable, LiteralOrVariable),
|
||||||
|
/// Computes the minimum of two numbers.
|
||||||
|
/// ## In Game
|
||||||
|
/// `min r? a(r?|num) b(r?|num)`
|
||||||
|
Min(LiteralOrVariable, LiteralOrVariable),
|
||||||
|
/// Computes the square root of a number.
|
||||||
|
/// ## In Game
|
||||||
|
/// `sqrt r? a(r?|num)`
|
||||||
|
Sqrt(LiteralOrVariable),
|
||||||
|
/// Gets a random number between 0 and 1.
|
||||||
|
/// ## In Game
|
||||||
|
/// `rand r?`
|
||||||
|
Rand,
|
||||||
|
/// Truncates a number by removing the decimal portion.
|
||||||
|
/// ## In Game
|
||||||
|
/// `trunc r? a(r?|num)`
|
||||||
|
Trunc(LiteralOrVariable),
|
||||||
|
|
||||||
|
/// Returns the angle in radians whose cosine is the specified number.
|
||||||
|
/// ## In Game
|
||||||
|
/// `acos r? a(r?|num)`
|
||||||
|
Acos(LiteralOrVariable),
|
||||||
|
|
||||||
|
/// Returns the angle in radians whose sine is the specified number.
|
||||||
|
/// ## In Game
|
||||||
|
/// `asin r? a(r?|num)`
|
||||||
|
Asin(LiteralOrVariable),
|
||||||
|
|
||||||
|
/// Returns the angle in radians whose tangent is the specified number.
|
||||||
|
/// ## In Game
|
||||||
|
/// `atan r? a(r?|num)`
|
||||||
|
Atan(LiteralOrVariable),
|
||||||
|
|
||||||
|
/// Returns the angle in radians whose tangent is the quotient of the specified numbers.
|
||||||
|
/// ## In Game
|
||||||
|
/// `atan2 r? a(r?|num) b(r?|num)`
|
||||||
|
Atan2(LiteralOrVariable, LiteralOrVariable),
|
||||||
|
|
||||||
|
/// Returns the cosine of the specified angle in radians.
|
||||||
|
/// ## In Game
|
||||||
|
/// cos r? a(r?|num)
|
||||||
|
Cos(LiteralOrVariable),
|
||||||
|
|
||||||
|
/// Returns the sine of the specified angle in radians.
|
||||||
|
/// ## In Game
|
||||||
|
/// `sin r? a(r?|num)`
|
||||||
|
Sin(LiteralOrVariable),
|
||||||
|
|
||||||
|
/// Returns the tangent of the specified angle in radians.
|
||||||
|
/// ## In Game
|
||||||
|
/// `tan r? a(r?|num)`
|
||||||
|
Tan(LiteralOrVariable),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum System {
|
||||||
|
/// Pauses execution for exactly 1 tick and then resumes.
|
||||||
|
/// ## In Game
|
||||||
|
/// yield
|
||||||
|
Yield,
|
||||||
|
/// Represents a function that can be called to sleep for a certain amount of time.
|
||||||
|
/// ## In Game
|
||||||
|
/// `sleep a(r?|num)`
|
||||||
|
Sleep(LiteralOrVariable),
|
||||||
|
/// Represents a function that can be called to load a variable from a device into a register.
|
||||||
|
/// ## In Game
|
||||||
|
/// `l r? d? logicType`
|
||||||
|
LoadVar(Literal, Literal),
|
||||||
|
/// Gets the in-game hash for a specific prefab name.
|
||||||
|
/// ## In Game
|
||||||
|
/// `HASH("prefabName")`
|
||||||
|
Hash(LiteralOrVariable),
|
||||||
|
/// Represents a function which will clear the stack for a provided device.
|
||||||
|
/// ## In Game
|
||||||
|
/// `clr d?`
|
||||||
|
StackClear(Literal),
|
||||||
|
/// Represents a function which reads a value from a device at a specific address and stores it in a register.
|
||||||
|
/// ## In Game
|
||||||
|
/// `get r? d? address(r?|num)`
|
||||||
|
Get(Literal, LiteralOrVariable),
|
||||||
|
/// Represents a function which loads a device variable into a register.
|
||||||
|
/// ## In Game
|
||||||
|
/// `l r? d? var`
|
||||||
|
/// ## Examples
|
||||||
|
/// `l r0 d0 Setting`
|
||||||
|
/// `l r1 d5 Pressure`
|
||||||
|
Load(String, LiteralOrVariable),
|
||||||
|
/// Represents a function which stores a setting into a specific device.
|
||||||
|
/// ## In Game
|
||||||
|
/// `s d? logicType r?`
|
||||||
|
/// ## Example
|
||||||
|
/// `s d0 Setting r0`
|
||||||
|
Store(String, LiteralOrVariable, LiteralOrVariable),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
/// This represents built in functions that cannot be overwritten, but can be invoked by the user as functions.
|
||||||
|
pub enum SysCall {
|
||||||
|
System(System),
|
||||||
|
/// Represents any mathmatical function that can be called.
|
||||||
|
Math(Math),
|
||||||
|
}
|
||||||
@@ -138,6 +138,13 @@ impl std::fmt::Display for InvocationExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum LiteralOrVariable {
|
||||||
|
Literal(Literal),
|
||||||
|
Variable(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
AssignmentExpression(AssignmentExpression),
|
AssignmentExpression(AssignmentExpression),
|
||||||
|
|||||||
Reference in New Issue
Block a user