commit
c44c33c26c
Binary file not shown.
BIN
editor/vscode/mclang-0.0.3.vsix
Normal file
BIN
editor/vscode/mclang-0.0.3.vsix
Normal file
Binary file not shown.
|
@ -2,7 +2,7 @@
|
||||||
"name": "mclang",
|
"name": "mclang",
|
||||||
"displayName": "mclang",
|
"displayName": "mclang",
|
||||||
"description": "Code highlighting for mclang",
|
"description": "Code highlighting for mclang",
|
||||||
"version": "0.0.2",
|
"version": "0.0.3",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git@github.com:mc-lang/mclang2.git"
|
"url": "git@github.com:mc-lang/mclang2.git"
|
||||||
|
|
|
@ -112,7 +112,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"comments": {
|
"comments": {
|
||||||
"disabled__patterns": [
|
"patterns": [
|
||||||
{
|
{
|
||||||
"name": "constant.other.character-class.regexp",
|
"name": "constant.other.character-class.regexp",
|
||||||
"match": "(?://\\s*)(TODO(O*)|FIXME).*"
|
"match": "(?://\\s*)(TODO(O*)|FIXME).*"
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{fs, path::PathBuf, io::{Write, BufWriter}, collections::HashMap};
|
use std::{fs, path::PathBuf, io::{Write, BufWriter}, collections::HashMap};
|
||||||
use crate::{constants::{Operator, OpType, KeywordType}, Args};
|
use crate::{constants::{Operator, OpType, KeywordType}, Args, warn, lerror};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use crate::compile::commands::linux_x86_64_compile_and_link;
|
use crate::compile::commands::linux_x86_64_compile_and_link;
|
||||||
use crate::constants::InstructionType;
|
use crate::constants::InstructionType;
|
||||||
|
@ -25,6 +25,7 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
of_o.set_extension("o");
|
of_o.set_extension("o");
|
||||||
of_a.set_extension("nasm");
|
of_a.set_extension("nasm");
|
||||||
|
|
||||||
|
let mut should_push_ret = false;
|
||||||
|
|
||||||
let file = fs::File::create(&of_a)?;
|
let file = fs::File::create(&of_a)?;
|
||||||
let mut writer = BufWriter::new(&file);
|
let mut writer = BufWriter::new(&file);
|
||||||
|
@ -71,11 +72,14 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
writeln!(writer, " add rsp, 40")?;
|
writeln!(writer, " add rsp, 40")?;
|
||||||
writeln!(writer, " ret")?;
|
writeln!(writer, " ret")?;
|
||||||
|
|
||||||
writeln!(writer, "global _start")?;
|
if crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode {
|
||||||
writeln!(writer, "_start:")?;
|
writeln!(writer, "global _start")?;
|
||||||
writeln!(writer, " lea rbp, [rel ret_stack]")?;
|
writeln!(writer, "_start:")?;
|
||||||
writeln!(writer, " call main")?;
|
writeln!(writer, " lea rbp, [rel ret_stack]")?;
|
||||||
writeln!(writer, " jmp end")?;
|
writeln!(writer, " call main")?;
|
||||||
|
writeln!(writer, " jmp end")?;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
let mut ti = 0;
|
let mut ti = 0;
|
||||||
|
@ -92,10 +96,11 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
writeln!(writer, " ;; -- {:?}", token.typ)?;
|
writeln!(writer, " ;; -- {:?}", token.typ)?;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if ti > 0 {
|
||||||
if ti != 0 && tokens[ti-1].typ == OpType::Keyword(KeywordType::Else) ||
|
if tokens[ti-1].typ == OpType::Keyword(KeywordType::Else) ||
|
||||||
tokens[ti-1].typ == OpType::Keyword(KeywordType::End){
|
tokens[ti-1].typ == OpType::Keyword(KeywordType::End){
|
||||||
writeln!(writer, "addr_{ti}:")?;
|
writeln!(writer, "addr_{ti}:")?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ti + 1 < tokens.len() && tokens[ti+1].typ == OpType::Keyword(KeywordType::End) {
|
if ti + 1 < tokens.len() && tokens[ti+1].typ == OpType::Keyword(KeywordType::End) {
|
||||||
|
@ -415,6 +420,12 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
InstructionType::Return => {
|
InstructionType::Return => {
|
||||||
|
|
||||||
|
if crate::config::ENABLE_EXPORTED_FUNCTIONS && should_push_ret {
|
||||||
|
writeln!(writer, " pop rdx")?;
|
||||||
|
should_push_ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
writeln!(writer, " sub rbp, 8")?;
|
writeln!(writer, " sub rbp, 8")?;
|
||||||
writeln!(writer, " mov rbx, qword [rbp]")?;
|
writeln!(writer, " mov rbx, qword [rbp]")?;
|
||||||
writeln!(writer, " push rbx")?;
|
writeln!(writer, " push rbx")?;
|
||||||
|
@ -429,7 +440,6 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
InstructionType::TypePtr |
|
InstructionType::TypePtr |
|
||||||
InstructionType::TypeInt |
|
InstructionType::TypeInt |
|
||||||
InstructionType::TypeVoid |
|
InstructionType::TypeVoid |
|
||||||
InstructionType::TypeStr |
|
|
||||||
InstructionType::TypeAny |
|
InstructionType::TypeAny |
|
||||||
InstructionType::Returns |
|
InstructionType::Returns |
|
||||||
InstructionType::With => {
|
InstructionType::With => {
|
||||||
|
@ -496,10 +506,16 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
writeln!(writer, " pop rbx")?;
|
writeln!(writer, " pop rbx")?;
|
||||||
writeln!(writer, " mov qword [rbp], rbx")?;
|
writeln!(writer, " mov qword [rbp], rbx")?;
|
||||||
writeln!(writer, " add rbp, 8")?;
|
writeln!(writer, " add rbp, 8")?;
|
||||||
functions.push(Function { loc: token.loc.clone(), name: token.text.clone() });
|
functions.push(Function { loc: token.loc.clone(), name: token.text.clone(), exter: false});
|
||||||
ti += 1;
|
ti += 1;
|
||||||
},
|
},
|
||||||
KeywordType::FunctionDone => {
|
KeywordType::FunctionDone => {
|
||||||
|
|
||||||
|
if crate::config::ENABLE_EXPORTED_FUNCTIONS && should_push_ret {
|
||||||
|
writeln!(writer, " pop rdx")?;
|
||||||
|
should_push_ret = false;
|
||||||
|
}
|
||||||
|
|
||||||
writeln!(writer, " sub rbp, 8")?;
|
writeln!(writer, " sub rbp, 8")?;
|
||||||
writeln!(writer, " mov rbx, qword [rbp]")?;
|
writeln!(writer, " mov rbx, qword [rbp]")?;
|
||||||
writeln!(writer, " push rbx")?;
|
writeln!(writer, " push rbx")?;
|
||||||
|
@ -509,16 +525,71 @@ pub fn compile(tokens: &[Operator], args: &Args) -> Result<i32>{
|
||||||
KeywordType::FunctionThen => ti += 1,
|
KeywordType::FunctionThen => ti += 1,
|
||||||
KeywordType::Function |
|
KeywordType::Function |
|
||||||
KeywordType::Include |
|
KeywordType::Include |
|
||||||
|
KeywordType::Inline |
|
||||||
|
KeywordType::Export |
|
||||||
KeywordType::Constant => unreachable!(),
|
KeywordType::Constant => unreachable!(),
|
||||||
|
KeywordType::FunctionDefExported => {
|
||||||
|
|
||||||
|
if !crate::config::ENABLE_EXPORTED_FUNCTIONS {
|
||||||
|
lerror!(&token.loc, "Experimental feature 'exported functions' is not enabled");
|
||||||
|
return Err(eyre!(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(writer, "global {}", token.text)?;
|
||||||
|
writeln!(writer, "{}:", token.text)?;
|
||||||
|
|
||||||
|
writeln!(writer, " pop rbx")?;
|
||||||
|
writeln!(writer, " mov qword [rbp], rbx")?;
|
||||||
|
writeln!(writer, " add rbp, 8")?;
|
||||||
|
warn!("External functions are highly experimental and should be treated as such");
|
||||||
|
if token.types.0 == 0 {
|
||||||
|
writeln!(writer, " ; no arguments")?;
|
||||||
|
} else {
|
||||||
|
if token.types.0 >= 1 {
|
||||||
|
writeln!(writer, " push rdi")?;
|
||||||
|
}
|
||||||
|
if token.types.0 >= 2 {
|
||||||
|
writeln!(writer, " push rsi")?;
|
||||||
|
}
|
||||||
|
if token.types.0 >= 3 {
|
||||||
|
writeln!(writer, " push rdx")?;
|
||||||
|
}
|
||||||
|
if token.types.0 >= 4 {
|
||||||
|
writeln!(writer, " push rcx")?;
|
||||||
|
}
|
||||||
|
if token.types.0 >= 5 {
|
||||||
|
writeln!(writer, " push r8")?;
|
||||||
|
}
|
||||||
|
if token.types.0 >= 6 {
|
||||||
|
writeln!(writer, " push r9")?;
|
||||||
|
}
|
||||||
|
if token.types.0 >= 7 {
|
||||||
|
lerror!(&token.loc, "More than 6 arguments in an external function is not supported");
|
||||||
|
return Err(eyre!(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if token.types.1 == 1 {
|
||||||
|
should_push_ret = true;
|
||||||
|
} else if token.types.1 > 1 {
|
||||||
|
lerror!(&token.loc, "More than 1 return arguments in an external function is not supported");
|
||||||
|
return Err(eyre!(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
functions.push(Function { loc: token.loc.clone(), name: token.text.clone(), exter: false});
|
||||||
|
ti += 1;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeln!(writer, "addr_{ti}:")?;
|
writeln!(writer, "addr_{ti}:")?;
|
||||||
writeln!(writer, "end:")?;
|
if crate::config::ENABLE_EXPORTED_FUNCTIONS && !args.lib_mode {
|
||||||
writeln!(writer, " mov rax, 60")?;
|
writeln!(writer, "end:")?;
|
||||||
writeln!(writer, " mov rdi, 0")?;
|
writeln!(writer, " mov rax, 60")?;
|
||||||
writeln!(writer, " syscall")?;
|
writeln!(writer, " mov rdi, 0")?;
|
||||||
|
writeln!(writer, " syscall")?;
|
||||||
|
}
|
||||||
writeln!(writer, "segment .data")?;
|
writeln!(writer, "segment .data")?;
|
||||||
for (i, s) in strings.iter().enumerate() {
|
for (i, s) in strings.iter().enumerate() {
|
||||||
let s_chars = s.chars().map(|c| (c as u32).to_string()).collect::<Vec<String>>();
|
let s_chars = s.chars().map(|c| (c as u32).to_string()).collect::<Vec<String>>();
|
||||||
|
|
|
@ -23,5 +23,6 @@ pub struct Memory {
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
pub loc: Loc,
|
pub loc: Loc,
|
||||||
pub name: String
|
pub name: String,
|
||||||
|
pub exter: bool,
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Prints out extra information
|
* Prints out extra information
|
||||||
*/
|
*/
|
||||||
pub const DEV_MODE: bool = true;
|
pub const DEV_MODE: bool = false;
|
||||||
|
|
||||||
pub const DEFAULT_OUT_FILE: &str = "a.out";
|
pub const DEFAULT_OUT_FILE: &str = "a.out";
|
||||||
pub const DEFAULT_INCLUDES: [&str;1] = [
|
pub const DEFAULT_INCLUDES: [&str;1] = [
|
||||||
|
@ -17,4 +17,10 @@ pub const DEFAULT_INCLUDES: [&str;1] = [
|
||||||
* if you have buffer overflow consider increasing these
|
* if you have buffer overflow consider increasing these
|
||||||
*/
|
*/
|
||||||
pub const MEM_SZ: usize = 640 * 1000; // 4kb
|
pub const MEM_SZ: usize = 640 * 1000; // 4kb
|
||||||
pub const STRING_SZ: usize = 640 * 1000; // 4kb
|
pub const STRING_SZ: usize = 640 * 1000; // 4kb
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Experimental options
|
||||||
|
*/
|
||||||
|
pub const ENABLE_EXPORTED_FUNCTIONS: bool = false;
|
|
@ -58,7 +58,7 @@ pub enum InstructionType {
|
||||||
TypePtr,
|
TypePtr,
|
||||||
TypeInt,
|
TypeInt,
|
||||||
TypeVoid,
|
TypeVoid,
|
||||||
TypeStr,
|
// TypeStr,
|
||||||
TypeAny,
|
TypeAny,
|
||||||
Returns,
|
Returns,
|
||||||
With,
|
With,
|
||||||
|
@ -84,8 +84,11 @@ pub enum KeywordType {
|
||||||
ConstantDef,
|
ConstantDef,
|
||||||
Function,
|
Function,
|
||||||
FunctionDef,
|
FunctionDef,
|
||||||
|
FunctionDefExported,
|
||||||
FunctionThen,
|
FunctionThen,
|
||||||
FunctionDone
|
FunctionDone,
|
||||||
|
Inline,
|
||||||
|
Export
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
@ -102,7 +105,8 @@ pub struct Operator{
|
||||||
pub text: String, //? only used for OpType::PushStr
|
pub text: String, //? only used for OpType::PushStr
|
||||||
pub addr: Option<usize>, //? only used for OpType::PushStr
|
pub addr: Option<usize>, //? only used for OpType::PushStr
|
||||||
pub jmp: usize,
|
pub jmp: usize,
|
||||||
pub loc: Loc
|
pub loc: Loc,
|
||||||
|
pub types: (usize, usize)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Operator {
|
impl Operator {
|
||||||
|
@ -115,13 +119,19 @@ impl Operator {
|
||||||
text,
|
text,
|
||||||
loc: (file, row, col),
|
loc: (file, row, col),
|
||||||
tok_typ,
|
tok_typ,
|
||||||
|
types: (0, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set_addr(mut self, addr: usize) -> Self {
|
pub fn set_addr(&mut self, addr: usize) -> Self {
|
||||||
self.addr = Some(addr);
|
self.addr = Some(addr);
|
||||||
self
|
(*self).clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn set_types(&mut self, args: usize, rets: usize) -> Self {
|
||||||
|
// self.types = (args, rets);
|
||||||
|
// (*self).clone()
|
||||||
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpType {
|
impl OpType {
|
||||||
|
@ -178,7 +188,6 @@ impl OpType {
|
||||||
InstructionType::TypePtr => "ptr",
|
InstructionType::TypePtr => "ptr",
|
||||||
InstructionType::TypeInt => "int",
|
InstructionType::TypeInt => "int",
|
||||||
InstructionType::TypeVoid => "void",
|
InstructionType::TypeVoid => "void",
|
||||||
InstructionType::TypeStr => "str",
|
|
||||||
InstructionType::Returns => "returns",
|
InstructionType::Returns => "returns",
|
||||||
InstructionType::With => "with",
|
InstructionType::With => "with",
|
||||||
InstructionType::TypeAny => "any",
|
InstructionType::TypeAny => "any",
|
||||||
|
@ -198,7 +207,10 @@ impl OpType {
|
||||||
KeywordType::FunctionThen => "then",
|
KeywordType::FunctionThen => "then",
|
||||||
KeywordType::FunctionDone => "done",
|
KeywordType::FunctionDone => "done",
|
||||||
KeywordType::ConstantDef => "constant Definition (internal)",
|
KeywordType::ConstantDef => "constant Definition (internal)",
|
||||||
KeywordType::FunctionDef => "function definition (internal)"
|
KeywordType::FunctionDef => "function definition (internal)",
|
||||||
|
KeywordType::FunctionDefExported => "extern function definition (internal)",
|
||||||
|
KeywordType::Inline => "inline",
|
||||||
|
KeywordType::Export => "export",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,7 +267,6 @@ pub enum Types {
|
||||||
Ptr,
|
Ptr,
|
||||||
Int,
|
Int,
|
||||||
Void,
|
Void,
|
||||||
Str,
|
|
||||||
Any
|
Any
|
||||||
// U8,
|
// U8,
|
||||||
// U16,
|
// U16,
|
||||||
|
|
|
@ -328,7 +328,6 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
|
||||||
InstructionType::TypePtr |
|
InstructionType::TypePtr |
|
||||||
InstructionType::TypeInt |
|
InstructionType::TypeInt |
|
||||||
InstructionType::TypeVoid |
|
InstructionType::TypeVoid |
|
||||||
InstructionType::TypeStr |
|
|
||||||
InstructionType::TypeAny |
|
InstructionType::TypeAny |
|
||||||
InstructionType::Returns |
|
InstructionType::Returns |
|
||||||
InstructionType::With => ip += 1,
|
InstructionType::With => ip += 1,
|
||||||
|
@ -362,6 +361,7 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
|
||||||
KeywordType::While | //* exept this one, this one should just skip over
|
KeywordType::While | //* exept this one, this one should just skip over
|
||||||
KeywordType::Memory |
|
KeywordType::Memory |
|
||||||
KeywordType::FunctionDef |
|
KeywordType::FunctionDef |
|
||||||
|
KeywordType::FunctionDefExported |
|
||||||
KeywordType::ConstantDef => {
|
KeywordType::ConstantDef => {
|
||||||
//? Disabled since we now pre run the whole program
|
//? Disabled since we now pre run the whole program
|
||||||
// constants.insert(op.text.clone(), Constant { loc: op.loc.clone(), name: op.text.clone(), value_i: Some(op.value), value_s: None, used: false });
|
// constants.insert(op.text.clone(), Constant { loc: op.loc.clone(), name: op.text.clone(), value_i: Some(op.value), value_s: None, used: false });
|
||||||
|
@ -378,6 +378,8 @@ pub fn run(ops: &[crate::constants::Operator]) -> Result<i32>{
|
||||||
KeywordType::FunctionThen => ip += 1,
|
KeywordType::FunctionThen => ip += 1,
|
||||||
KeywordType::Constant |
|
KeywordType::Constant |
|
||||||
KeywordType::Function |
|
KeywordType::Function |
|
||||||
|
KeywordType::Inline |
|
||||||
|
KeywordType::Export |
|
||||||
KeywordType::Include => unreachable!(),
|
KeywordType::Include => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,6 +409,9 @@ pub fn pre_run(ops: &[Operator]) -> Defineds {
|
||||||
OpType::Keyword(KeywordType::Memory) => {
|
OpType::Keyword(KeywordType::Memory) => {
|
||||||
defineds.memories.insert(op.addr.unwrap(), Memory { size: op.value, loc: op.loc.clone(), id: op.addr.unwrap() });
|
defineds.memories.insert(op.addr.unwrap(), Memory { size: op.value, loc: op.loc.clone(), id: op.addr.unwrap() });
|
||||||
},
|
},
|
||||||
|
OpType::Keyword(KeywordType::FunctionDefExported) => {
|
||||||
|
|
||||||
|
}
|
||||||
OpType::Keyword(KeywordType::FunctionDef) => {
|
OpType::Keyword(KeywordType::FunctionDef) => {
|
||||||
defineds.functions.insert(op.text.clone(), Function { loc: op.loc.clone(), name: op.text.clone(), id: ip });
|
defineds.functions.insert(op.text.clone(), Function { loc: op.loc.clone(), name: op.text.clone(), id: ip });
|
||||||
},
|
},
|
||||||
|
|
|
@ -57,6 +57,9 @@ pub struct Args {
|
||||||
#[arg(long, short='O', default_value_t=String::from("0"))]
|
#[arg(long, short='O', default_value_t=String::from("0"))]
|
||||||
optimisation: String,
|
optimisation: String,
|
||||||
|
|
||||||
|
// disables the main function
|
||||||
|
#[arg(long="lib")]
|
||||||
|
lib_mode: bool
|
||||||
//#[arg(long, short='F')]
|
//#[arg(long, short='F')]
|
||||||
//features: Vec<String>,
|
//features: Vec<String>,
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,7 @@ pub fn cross_ref(mut program: Vec<Operator>) -> Result<Vec<Operator>> {
|
||||||
program[ip].jmp = program[block_ip].jmp;
|
program[ip].jmp = program[block_ip].jmp;
|
||||||
program[block_ip].jmp = ip + 1;
|
program[block_ip].jmp = ip + 1;
|
||||||
}
|
}
|
||||||
OpType::Keyword(KeywordType::FunctionThen) => {
|
|
||||||
program[ip].typ = OpType::Instruction(InstructionType::Return);
|
|
||||||
}
|
|
||||||
OpType::Keyword(KeywordType::Memory | KeywordType::Constant) => (),
|
OpType::Keyword(KeywordType::Memory | KeywordType::Constant) => (),
|
||||||
|
|
||||||
a => {
|
a => {
|
||||||
|
@ -208,6 +206,8 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
|
||||||
"fn" => OpType::Keyword(KeywordType::Function),
|
"fn" => OpType::Keyword(KeywordType::Function),
|
||||||
"then" => OpType::Keyword(KeywordType::FunctionThen),
|
"then" => OpType::Keyword(KeywordType::FunctionThen),
|
||||||
"done" => OpType::Keyword(KeywordType::FunctionDone),
|
"done" => OpType::Keyword(KeywordType::FunctionDone),
|
||||||
|
"inline" => OpType::Keyword(KeywordType::Inline),
|
||||||
|
"export" => OpType::Keyword(KeywordType::Export),
|
||||||
"return" => OpType::Instruction(InstructionType::Return),
|
"return" => OpType::Instruction(InstructionType::Return),
|
||||||
"returns" => OpType::Instruction(InstructionType::Returns),
|
"returns" => OpType::Instruction(InstructionType::Returns),
|
||||||
"bool" => OpType::Instruction(InstructionType::TypeBool),
|
"bool" => OpType::Instruction(InstructionType::TypeBool),
|
||||||
|
@ -215,7 +215,6 @@ pub fn lookup_word<P: Deref<Target = Loc>>(s: &str, _pos: P) -> OpType {
|
||||||
"ptr" => OpType::Instruction(InstructionType::TypePtr),
|
"ptr" => OpType::Instruction(InstructionType::TypePtr),
|
||||||
"void" => OpType::Instruction(InstructionType::TypeVoid),
|
"void" => OpType::Instruction(InstructionType::TypeVoid),
|
||||||
"any" => OpType::Instruction(InstructionType::TypeAny),
|
"any" => OpType::Instruction(InstructionType::TypeAny),
|
||||||
"str" => OpType::Instruction(InstructionType::TypeStr),
|
|
||||||
"with" => OpType::Instruction(InstructionType::With),
|
"with" => OpType::Instruction(InstructionType::With),
|
||||||
_ => OpType::Instruction(InstructionType::None)
|
_ => OpType::Instruction(InstructionType::None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,9 @@ use crate::parser::lookup_word;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
pub loc: Loc,
|
pub loc: Loc,
|
||||||
pub name: String
|
pub name: String,
|
||||||
|
pub inline: bool,
|
||||||
|
pub tokens: Option<Vec<Operator>>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -62,20 +64,21 @@ impl<'a> Preprocessor<'a> {
|
||||||
pub fn preprocess(&mut self) -> Result<&mut Preprocessor<'a>>{
|
pub fn preprocess(&mut self) -> Result<&mut Preprocessor<'a>>{
|
||||||
// println!("pre: has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
|
// println!("pre: has do tokens: {:?}", self.program.iter().map(|t| if t.typ == OpType::Keyword(KeywordType::Do) {Some(t)} else {None} ).collect::<Vec<Option<&Operator>>>());
|
||||||
|
|
||||||
|
let mut f_inline = false;
|
||||||
|
let mut f_extern = false;
|
||||||
|
|
||||||
let mut program: Vec<Operator> = Vec::new();
|
let mut program: Vec<Operator> = Vec::new();
|
||||||
|
|
||||||
let mut rtokens = self.program.clone();
|
let mut rtokens = self.program.clone();
|
||||||
rtokens.reverse();
|
rtokens.reverse();
|
||||||
while !rtokens.is_empty() {
|
while !rtokens.is_empty() {
|
||||||
let mut token = rtokens.pop().unwrap();
|
let mut op = rtokens.pop().unwrap();
|
||||||
// println!("{token:?}");
|
// println!("{token:?}");
|
||||||
let op_type = token.typ.clone();
|
let op_type = op.typ.clone();
|
||||||
match token.clone() {
|
match op_type {
|
||||||
|
OpType::Keyword(KeywordType::Include) => {
|
||||||
|
|
||||||
_ if op_type == OpType::Keyword(KeywordType::Include) => {
|
|
||||||
if rtokens.is_empty() {
|
if rtokens.is_empty() {
|
||||||
lerror!(&token.loc, "Include path not found, expected {} but found nothing", TokenType::String.human());
|
lerror!(&op.loc, "Include path not found, expected {} but found nothing", TokenType::String.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,9 +130,10 @@ impl<'a> Preprocessor<'a> {
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
_ if op_type == OpType::Keyword(KeywordType::Memory) => {
|
|
||||||
|
OpType::Keyword(KeywordType::Memory) => {
|
||||||
if rtokens.is_empty() {
|
if rtokens.is_empty() {
|
||||||
lerror!(&token.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human());
|
lerror!(&op.loc, "Memory name not found, expected {} but found nothing", TokenType::String.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,19 +163,20 @@ impl<'a> Preprocessor<'a> {
|
||||||
|
|
||||||
|
|
||||||
if res.len() != 1 {
|
if res.len() != 1 {
|
||||||
lerror!(&token.loc, "Expected 1 number, got {:?}", res);
|
lerror!(&op.loc, "Expected 1 number, got {:?}", res);
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
token.value = res[0];
|
op.value = res[0];
|
||||||
token.addr = Some(self.memories.len());
|
op.addr = Some(self.memories.len());
|
||||||
program.push(token.clone());
|
program.push(op.clone());
|
||||||
|
|
||||||
self.memories.insert(name.text, Memory { loc: token.loc, id: self.memories.len() });
|
self.memories.insert(name.text, Memory { loc: op.loc, id: self.memories.len() });
|
||||||
|
|
||||||
}
|
}
|
||||||
_ if op_type == OpType::Keyword(KeywordType::Function) => {
|
|
||||||
|
OpType::Keyword(KeywordType::Function) => {
|
||||||
if rtokens.is_empty() {
|
if rtokens.is_empty() {
|
||||||
lerror!(&token.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human());
|
lerror!(&op.loc, "Function name not found, expected {} but found nothing", TokenType::Word.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,20 +211,130 @@ impl<'a> Preprocessor<'a> {
|
||||||
self.is_word_available(&name, KeywordType::Function)?;
|
self.is_word_available(&name, KeywordType::Function)?;
|
||||||
|
|
||||||
|
|
||||||
self.functions.insert(name.text.clone(), Function{
|
if f_inline {
|
||||||
loc: name.loc.clone(),
|
f_inline = false;
|
||||||
name: name.text.clone(),
|
let mut prog: Vec<Operator> = Vec::new();
|
||||||
});
|
let mut depth = -1;
|
||||||
|
while !rtokens.is_empty() {
|
||||||
|
let op = rtokens.pop().unwrap();
|
||||||
|
|
||||||
let mut fn_def = token.clone();
|
match op.typ.clone() {
|
||||||
fn_def.typ = OpType::Keyword(KeywordType::FunctionDef);
|
OpType::Instruction(i) => {
|
||||||
fn_def.text = name.text;
|
match i {
|
||||||
// println!("{:?}", token);
|
InstructionType::TypeAny |
|
||||||
program.push(fn_def);
|
InstructionType::TypeBool |
|
||||||
|
InstructionType::TypeInt |
|
||||||
|
InstructionType::TypePtr |
|
||||||
|
InstructionType::With |
|
||||||
|
InstructionType::Returns |
|
||||||
|
InstructionType::TypeVoid => {
|
||||||
|
if depth >= 0 {
|
||||||
|
prog.push(op);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => prog.push(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OpType::Keyword(k) => {
|
||||||
|
match k {
|
||||||
|
KeywordType::Inline |
|
||||||
|
KeywordType::Include => {
|
||||||
|
todo!("make error")
|
||||||
|
},
|
||||||
|
KeywordType::FunctionThen => {
|
||||||
|
if depth >= 0 {
|
||||||
|
prog.push(op);
|
||||||
|
}
|
||||||
|
depth += 1;
|
||||||
|
},
|
||||||
|
KeywordType::FunctionDone => {
|
||||||
|
if depth == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
depth -= 1;
|
||||||
|
},
|
||||||
|
_ => prog.push(op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let mut pre = self.clone();
|
||||||
|
pre.program = prog;
|
||||||
|
pre.preprocess()?;
|
||||||
|
prog = pre.get_ops();
|
||||||
|
|
||||||
|
self.functions.insert(name.text.clone(), Function{
|
||||||
|
loc: name.loc.clone(),
|
||||||
|
name: name.text.clone(),
|
||||||
|
inline: true,
|
||||||
|
tokens: Some(prog)
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if f_extern {
|
||||||
|
f_extern = false;
|
||||||
|
self.functions.insert(name.text.clone(), Function{
|
||||||
|
loc: name.loc.clone(),
|
||||||
|
name: name.text.clone(),
|
||||||
|
inline: false,
|
||||||
|
tokens: None
|
||||||
|
});
|
||||||
|
let mut a: Vec<Operator> = Vec::new();
|
||||||
|
let mut fn_def = op.clone();
|
||||||
|
a.push(rtokens.pop().unwrap());
|
||||||
|
let mut ret = false;
|
||||||
|
while !rtokens.is_empty() {
|
||||||
|
let op = rtokens.pop().unwrap();
|
||||||
|
// println!("{:?}",op);
|
||||||
|
a.push(op.clone());
|
||||||
|
if op.typ == OpType::Instruction(InstructionType::Returns) {
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if op.typ == OpType::Keyword(KeywordType::FunctionThen) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if op.typ == OpType::Instruction(InstructionType::TypeBool) ||
|
||||||
|
op.typ == OpType::Instruction(InstructionType::TypeInt) ||
|
||||||
|
op.typ == OpType::Instruction(InstructionType::TypePtr) {
|
||||||
|
|
||||||
|
if ret {
|
||||||
|
fn_def.types.1 += 1;
|
||||||
|
} else {
|
||||||
|
fn_def.types.0 += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn_def.typ = OpType::Keyword(KeywordType::FunctionDefExported);
|
||||||
|
fn_def.text = name.text;
|
||||||
|
// fn_def.set_types(args, rets);
|
||||||
|
// println!("{:?}", fn_def.types);
|
||||||
|
program.push(fn_def);
|
||||||
|
program.append(&mut a);
|
||||||
|
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
self.functions.insert(name.text.clone(), Function{
|
||||||
|
loc: name.loc.clone(),
|
||||||
|
name: name.text.clone(),
|
||||||
|
inline: false,
|
||||||
|
tokens: None
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut fn_def = op.clone();
|
||||||
|
fn_def.typ = OpType::Keyword(KeywordType::FunctionDef);
|
||||||
|
fn_def.text = name.text;
|
||||||
|
// println!("{:?}", token);
|
||||||
|
program.push(fn_def);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ if op_type == OpType::Keyword(KeywordType::Constant) => {
|
|
||||||
|
OpType::Keyword(KeywordType::Constant) => {
|
||||||
if rtokens.is_empty() {
|
if rtokens.is_empty() {
|
||||||
lerror!(&token.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human());
|
lerror!(&op.loc, "Constant name not found, expected {} but found nothing", TokenType::Word.human());
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
// println!("{token:?}");
|
// println!("{token:?}");
|
||||||
|
@ -263,7 +378,7 @@ impl<'a> Preprocessor<'a> {
|
||||||
|
|
||||||
// println!("{:?}", self.constants);
|
// println!("{:?}", self.constants);
|
||||||
|
|
||||||
let mut const_def = token.clone();
|
let mut const_def = op.clone();
|
||||||
const_def.typ = OpType::Keyword(KeywordType::ConstantDef);
|
const_def.typ = OpType::Keyword(KeywordType::ConstantDef);
|
||||||
const_def.text = name.text;
|
const_def.text = name.text;
|
||||||
|
|
||||||
|
@ -271,14 +386,14 @@ impl<'a> Preprocessor<'a> {
|
||||||
if item.tok_typ == TokenType::Int {
|
if item.tok_typ == TokenType::Int {
|
||||||
const_def.value = item.value;
|
const_def.value = item.value;
|
||||||
} else {
|
} else {
|
||||||
lerror!(&token.loc, "For now only {:?} is allowed in constants", TokenType::Int);
|
lerror!(&op.loc, "For now only {:?} is allowed in constants", TokenType::Int);
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
let posibly_end = rtokens.pop();
|
let posibly_end = rtokens.pop();
|
||||||
// println!("end: {posibly_end:?}");
|
// println!("end: {posibly_end:?}");
|
||||||
if posibly_end.is_none() || posibly_end.unwrap().typ != OpType::Keyword(KeywordType::End) {
|
if posibly_end.is_none() || posibly_end.unwrap().typ != OpType::Keyword(KeywordType::End) {
|
||||||
lerror!(&token.loc, "Constant was not closed with an 'end' instruction, expected 'end' but found nothing");
|
lerror!(&op.loc, "Constant was not closed with an 'end' instruction, expected 'end' but found nothing");
|
||||||
return Err(eyre!(""));
|
return Err(eyre!(""));
|
||||||
}
|
}
|
||||||
// token.value =
|
// token.value =
|
||||||
|
@ -286,9 +401,32 @@ impl<'a> Preprocessor<'a> {
|
||||||
program.push(const_def);
|
program.push(const_def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpType::Keyword(KeywordType::Inline) => {
|
||||||
|
if f_extern {
|
||||||
|
lerror!(&op.loc, "Function is already marked as extern, function cannot be inline and extern at the same time");
|
||||||
|
return Err(eyre!(""));
|
||||||
|
} else if f_inline {
|
||||||
|
lerror!(&op.loc, "Function is already marked as inline, remove this inline Keyword");
|
||||||
|
return Err(eyre!(""));
|
||||||
|
} else {
|
||||||
|
f_inline = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OpType::Keyword(KeywordType::Export) => {
|
||||||
|
if f_inline {
|
||||||
|
lerror!(&op.loc, "Function is already marked as inline, function cannot be inline and extern at the same time");
|
||||||
|
return Err(eyre!(""));
|
||||||
|
} else if f_extern {
|
||||||
|
lerror!(&op.loc, "Function is already marked as extern, remove this extern Keyword");
|
||||||
|
return Err(eyre!(""));
|
||||||
|
} else {
|
||||||
|
f_extern = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
|
program.push(op);
|
||||||
program.push(token);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,6 +441,7 @@ impl<'a> Preprocessor<'a> {
|
||||||
f.typ != OpType::Instruction(InstructionType::FnCall) &&
|
f.typ != OpType::Instruction(InstructionType::FnCall) &&
|
||||||
f.typ != OpType::Instruction(InstructionType::MemUse) &&
|
f.typ != OpType::Instruction(InstructionType::MemUse) &&
|
||||||
f.typ != OpType::Keyword(KeywordType::FunctionDef) &&
|
f.typ != OpType::Keyword(KeywordType::FunctionDef) &&
|
||||||
|
f.typ != OpType::Keyword(KeywordType::FunctionDefExported) &&
|
||||||
f.typ != OpType::Keyword(KeywordType::ConstantDef) &&
|
f.typ != OpType::Keyword(KeywordType::ConstantDef) &&
|
||||||
f.typ != OpType::Instruction(InstructionType::ConstUse) {
|
f.typ != OpType::Instruction(InstructionType::ConstUse) {
|
||||||
lookup_word(&f.text, &f.loc)
|
lookup_word(&f.text, &f.loc)
|
||||||
|
@ -334,15 +473,18 @@ impl<'a> Preprocessor<'a> {
|
||||||
if op.tok_typ == TokenType::Word {
|
if op.tok_typ == TokenType::Word {
|
||||||
match op_type {
|
match op_type {
|
||||||
OpType::Instruction(InstructionType::None) => {
|
OpType::Instruction(InstructionType::None) => {
|
||||||
let m = self.functions.get(&op.text);
|
let m = self.functions.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__"));
|
||||||
let mem = self.memories.get(&op.text);
|
let mem = self.memories.get(&op.text);
|
||||||
let cons = self.constants.get(&op.text);
|
let cons = self.constants.get(&op.text.clone().replace('(', "__OP_PAREN__").replace(')', "__CL_PAREN__"));
|
||||||
if let Some(m) = m {
|
if let Some(m) = m {
|
||||||
// println!("------ FOUND FUNCTION {} -----------", m.name);
|
if m.inline {
|
||||||
let mut t = op.clone();
|
program.append(&mut m.tokens.clone().unwrap());
|
||||||
t.typ = OpType::Instruction(InstructionType::FnCall);
|
} else {
|
||||||
t.text = m.name.clone();
|
let mut t = op.clone();
|
||||||
program.push(t.clone());
|
t.typ = OpType::Instruction(InstructionType::FnCall);
|
||||||
|
t.text = m.name.clone();
|
||||||
|
program.push(t.clone());
|
||||||
|
}
|
||||||
|
|
||||||
// println!("##### {:?}", t);
|
// println!("##### {:?}", t);
|
||||||
} else if let Some(mem) = mem {
|
} else if let Some(mem) = mem {
|
||||||
|
|
|
@ -62,9 +62,10 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
||||||
stack_pop(&mut stack, &op, &[Types::Bool])?;
|
stack_pop(&mut stack, &op, &[Types::Bool])?;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
KeywordType::FunctionDefExported |
|
||||||
KeywordType::FunctionDef => {
|
KeywordType::FunctionDef => {
|
||||||
let name = op.text.clone();
|
let name = op.text.clone();
|
||||||
|
// println!("{:?}", name);
|
||||||
if let Some(p) = rtokens.pop() {
|
if let Some(p) = rtokens.pop() {
|
||||||
if p.typ != OpType::Instruction(InstructionType::With){
|
if p.typ != OpType::Instruction(InstructionType::With){
|
||||||
lerror!(&op.loc, "Expected {:?}, got {:?}", OpType::Instruction(InstructionType::With), p.typ);
|
lerror!(&op.loc, "Expected {:?}, got {:?}", OpType::Instruction(InstructionType::With), p.typ);
|
||||||
|
@ -105,8 +106,6 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Types::Void
|
Types::Void
|
||||||
} else if op.typ == OpType::Instruction(InstructionType::TypeStr) {
|
|
||||||
Types::Str
|
|
||||||
} else if op.typ == OpType::Instruction(InstructionType::TypeAny) {
|
} else if op.typ == OpType::Instruction(InstructionType::TypeAny) {
|
||||||
Types::Any
|
Types::Any
|
||||||
} else {
|
} else {
|
||||||
|
@ -176,7 +175,12 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
||||||
},
|
},
|
||||||
KeywordType::FunctionThen |
|
KeywordType::FunctionThen |
|
||||||
KeywordType::FunctionDone |
|
KeywordType::FunctionDone |
|
||||||
KeywordType::Function => unreachable!(),
|
KeywordType::Inline |
|
||||||
|
KeywordType::Export |
|
||||||
|
KeywordType::Function => {
|
||||||
|
println!("{:?}", op);
|
||||||
|
unreachable!()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
OpType::Instruction(instruction) => {
|
OpType::Instruction(instruction) => {
|
||||||
|
@ -330,7 +334,10 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
||||||
InstructionType::FnCall => {
|
InstructionType::FnCall => {
|
||||||
stack_snapshots.push(stack.clone());
|
stack_snapshots.push(stack.clone());
|
||||||
|
|
||||||
let f = functions.get(&op.text).unwrap().clone();
|
let f = if let Some(f) = functions.get(&op.text) {f} else {
|
||||||
|
lerror!(&op.loc, "Could not find function {}", op.text);
|
||||||
|
return Err(eyre!(""));
|
||||||
|
};
|
||||||
|
|
||||||
// in_function = (op.text.clone(), f.clone(), op.loc.clone());
|
// in_function = (op.text.clone(), f.clone(), op.loc.clone());
|
||||||
|
|
||||||
|
@ -360,7 +367,6 @@ pub fn typecheck(ops: Vec<Operator>, args: &Args, init_types: Option<Vec<Types>>
|
||||||
InstructionType::TypeInt |
|
InstructionType::TypeInt |
|
||||||
InstructionType::TypeVoid |
|
InstructionType::TypeVoid |
|
||||||
InstructionType::TypeAny |
|
InstructionType::TypeAny |
|
||||||
InstructionType::TypeStr |
|
|
||||||
InstructionType::Returns |
|
InstructionType::Returns |
|
||||||
InstructionType::With => (),
|
InstructionType::With => (),
|
||||||
InstructionType::ConstUse => {
|
InstructionType::ConstUse => {
|
||||||
|
|
13
test.mcl
13
test.mcl
|
@ -1,5 +1,12 @@
|
||||||
include "std.mcl"
|
// include "std.mcl"
|
||||||
|
fn mcl_print with int ptr returns void then
|
||||||
|
1 1 syscall3 drop
|
||||||
|
done
|
||||||
|
|
||||||
|
fn mcl_dump with int returns void then
|
||||||
|
_dbg_print
|
||||||
|
done
|
||||||
|
|
||||||
fn main with void returns void then
|
fn main with void returns void then
|
||||||
"hi\n" puts
|
"hi\n" mcl_print
|
||||||
done
|
done
|
||||||
|
|
Loading…
Reference in New Issue
Block a user