2022-12-05 00:38:20 +01:00
use core ::panic ;
2022-12-14 04:12:03 +01:00
use std ::collections ::HashMap ;
2022-11-29 02:04:01 +01:00
use std ::env ;
use std ::fs ;
2022-12-14 07:57:51 +01:00
use std ::iter ::Peekable ;
2023-01-23 05:28:13 +01:00
use std ::path ::PathBuf ;
2023-01-05 00:19:29 +01:00
use std ::process ::Command ;
use std ::process ::Stdio ;
2022-12-05 00:38:20 +01:00
use std ::process ::exit ;
2023-01-09 12:23:01 +01:00
use std ::time ::Instant ;
2022-11-29 02:04:01 +01:00
2022-12-05 00:38:20 +01:00
#[ derive(Debug, Clone, PartialEq) ]
2022-11-29 02:04:01 +01:00
enum Token
{
StringLit ( String , i32 , i32 ) ,
2022-12-14 07:57:51 +01:00
IntLit ( String , i32 , i32 ) ,
2022-12-14 20:39:51 +01:00
BoolLit ( String , i32 , i32 ) ,
2022-12-05 00:38:20 +01:00
Keyword ( String , i32 , i32 ) ,
2022-12-21 21:48:52 +01:00
Apply ( String , String , i32 , i32 ) ,
2023-01-23 03:58:53 +01:00
Import ( i32 , i32 ) ,
2022-12-05 00:38:20 +01:00
}
2022-12-14 04:12:03 +01:00
2022-12-05 00:38:20 +01:00
enum TokenizerState
{
Whitespace ,
Quote ,
Keyword ,
Comment ,
}
2022-12-31 16:09:55 +01:00
#[ derive(Debug,Clone,Copy, PartialEq) ]
2022-12-05 00:38:20 +01:00
enum Datatype
{
Int ,
String ,
2022-12-14 20:39:51 +01:00
Bool ,
2022-12-14 07:57:51 +01:00
//Pointer,
2022-12-31 16:09:55 +01:00
// Any,
2022-12-05 00:38:20 +01:00
}
2022-12-31 16:09:55 +01:00
// impl PartialEq for Datatype
// {
// fn eq(&self, other: &Self) -> bool
// {
// core::mem::discriminant(self) == core::mem::discriminant(&Datatype::Any) ||
// core::mem::discriminant(other) == core::mem::discriminant(&Datatype::Any) ||
// core::mem::discriminant(self) == core::mem::discriminant(other)
// }
// }
2022-12-14 07:57:51 +01:00
2022-12-05 00:38:20 +01:00
#[ derive(Debug) ]
struct Function
{
name : String ,
ins : Vec < Datatype > ,
outs : Vec < Datatype > ,
2022-12-14 07:57:51 +01:00
content : Vec < Operation > ,
}
2022-12-21 21:48:52 +01:00
#[ derive(Debug) ]
struct Arr
{
name : String ,
datatype : Datatype ,
length : i64 ,
data : Vec < String > ,
}
2022-12-14 07:57:51 +01:00
#[ derive(Debug) ]
enum Operation
{
Enqueue ( Datatype , String , i32 , i32 ) ,
Dequeue ( i32 , i32 ) ,
2022-12-14 11:46:39 +01:00
// TODO: req can be implemented in terms of dup and dequeue
2022-12-14 08:14:27 +01:00
Requeue ( i32 , i32 ) ,
2022-12-14 11:46:39 +01:00
Swap ( i32 , i32 ) ,
Dup ( i32 , i32 ) ,
2022-12-14 07:57:51 +01:00
Intrinsic ( String , i32 , i32 ) ,
FunctionCall ( String , i32 , i32 ) ,
If ( Vec < Operation > , Option < Vec < Operation > > , i32 , i32 ) ,
While ( Vec < Operation > , i32 , i32 ) ,
2022-12-21 21:48:52 +01:00
Apply ( String , String , i32 , i32 ) ,
2022-12-15 20:34:56 +01:00
Depth ( i32 , i32 ) ,
QueueDiagnostic ( i32 , i32 ) ,
2023-01-03 20:39:08 +01:00
Interrupt ( i32 , i32 ) ,
2022-11-29 02:04:01 +01:00
}
fn main ( )
{
2022-12-14 04:12:03 +01:00
let intrinsics : HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > = HashMap ::from (
[
2022-12-31 16:09:55 +01:00
( " print " , ( Vec ::from ( [ Datatype ::String ] ) , Vec ::new ( ) ) ) ,
( " println " , ( Vec ::from ( [ Datatype ::String ] ) , Vec ::new ( ) ) ) ,
( " intToStr " , ( Vec ::from ( [ Datatype ::Int ] ) , Vec ::from ( [ Datatype ::String ] ) ) ) ,
2022-12-14 07:57:51 +01:00
( " - " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Int ] ) ) ) ,
2022-12-14 11:46:39 +01:00
( " + " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Int ] ) ) ) ,
2022-12-22 10:29:25 +01:00
( " * " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Int ] ) ) ) ,
2023-07-28 03:01:13 +02:00
( " divmod " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) ) ) ,
2022-12-14 20:39:51 +01:00
( " < " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Bool ] ) ) ) ,
( " > " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Bool ] ) ) ) ,
2022-12-22 10:29:25 +01:00
( " >= " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Bool ] ) ) ) ,
2023-01-03 20:39:08 +01:00
( " <= " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Bool ] ) ) ) ,
2022-12-14 20:39:51 +01:00
( " == " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Bool ] ) ) ) ,
( " != " , ( Vec ::from ( [ Datatype ::Int , Datatype ::Int ] ) , Vec ::from ( [ Datatype ::Bool ] ) ) ) ,
2022-12-22 10:29:25 +01:00
( " && " , ( Vec ::from ( [ Datatype ::Bool , Datatype ::Bool ] ) , Vec ::from ( [ Datatype ::Bool ] ) ) ) ,
2022-12-14 04:12:03 +01:00
] ) ;
2022-11-29 02:04:01 +01:00
let args : Vec < String > = env ::args ( ) . collect ( ) ;
2022-12-05 00:38:20 +01:00
if args . len ( ) < 2
{
usage ( )
}
2022-12-14 07:57:51 +01:00
let mut debug = false ;
2022-12-14 09:34:41 +01:00
let mut interpret = false ;
2023-01-05 00:19:29 +01:00
let mut run = false ;
2022-12-14 07:57:51 +01:00
for arg in & args [ 3 .. ]
{
match arg . as_str ( )
{
" -d " | " --debug " = > debug = true ,
2022-12-14 09:34:41 +01:00
" -i " | " --interpret " = > interpret = true ,
2023-01-05 00:19:29 +01:00
" -r " | " --run " = > run = true ,
2022-12-14 07:57:51 +01:00
_ = > panic! ( " Unknown option {} " , arg ) ,
}
}
2022-11-29 02:04:01 +01:00
match args [ 1 ] . as_str ( )
{
2022-12-15 21:53:01 +01:00
" -t " | " --test " = >
{
2022-12-18 04:05:50 +01:00
let mut count = 0 ;
2022-12-15 21:53:01 +01:00
for f in fs ::read_dir ( & args [ 2 ] ) . unwrap ( )
{
let f = f . unwrap ( ) ;
2022-12-31 16:12:53 +01:00
let file_content = fs ::read_to_string ( f . path ( ) ) . unwrap ( ) . replace ( " \r \n " , " \n " ) ;
2022-12-19 12:13:40 +01:00
println! ( " ========NOW TESTING {:?} ======== " , f . path ( ) ) ;
2023-01-23 05:28:13 +01:00
match compile ( & file_content , f . path ( ) . to_str ( ) . unwrap ( ) , & intrinsics , interpret , run , debug )
2022-12-15 21:53:01 +01:00
{
2022-12-18 04:05:50 +01:00
Ok ( maybe_msg ) = >
{
2022-12-19 12:13:40 +01:00
println! ( " ---Successfully parsed {:?} --- " , f . path ( ) ) ;
2022-12-18 04:05:50 +01:00
if let Some ( msg ) = & maybe_msg
{
print! ( " ---Output--- \n ' {} ' \n " , msg ) ;
}
2023-12-22 22:13:17 +01:00
let expected = & format! ( " //valid, {} :END: " , maybe_msg . unwrap_or ( String ::new ( ) ) . replace ( '\n' , " \n // " ) ) ;
2022-12-18 04:05:50 +01:00
if file_content . starts_with ( expected )
{
println! ( " ===PASSED=== " ) ;
count + = 1 ;
}
2022-12-21 21:48:52 +01:00
else if let Some ( index ) = file_content . find ( " :END: " )
2022-12-18 04:05:50 +01:00
{
let expected_output = file_content [ 8 .. index ] . replace ( " \n // " , " \n " ) ;
println! ( " \n ===FAILED=== \n Expected the output to be \n ' {} ' \n ( {} ) " , expected_output , expected ) ;
}
else
{
panic! ( " Could not find an ending marker (:END:) for the expected output in {:?} " , f . file_name ( ) ) ;
}
}
Err ( msg ) = >
{
println! ( " ERROR: {} " , msg ) ;
2023-12-22 22:13:17 +01:00
if file_content . starts_with ( & format! ( " //invalid, {} :END: " , msg . replace ( '\n' , " \n // " ) ) )
2022-12-18 04:05:50 +01:00
{
println! ( " ===PASSED=== " ) ;
count + = 1 ;
}
2022-12-21 21:48:52 +01:00
else if file_content . starts_with ( " //invalid, " )
2022-12-18 04:05:50 +01:00
{
2022-12-21 21:48:52 +01:00
if let Some ( index ) = file_content . find ( " :END: " )
{
2023-12-22 22:13:17 +01:00
let expected = & format! ( " //invalid, {} :END: " , msg . replace ( '\n' , " \n // " ) ) ;
2022-12-21 21:48:52 +01:00
let expected_output = file_content [ 10 .. index ] . replace ( " \n // " , " \n " ) ;
2023-01-11 02:33:30 +01:00
println! ( " \n ===FAILED=== \n Expected the output to be \n ' {} ' \n ( {} ) " , expected_output , expected ) ;
2022-12-21 21:48:52 +01:00
}
else
{
panic! ( " Could not find an ending marker (:END:) for the expected output in {:?} " , f . file_name ( ) ) ;
}
2022-12-18 04:05:50 +01:00
}
else
{
2022-12-21 21:48:52 +01:00
println! ( " Unexpected error " ) ;
2022-12-18 04:05:50 +01:00
}
}
2022-12-15 21:53:01 +01:00
}
}
2022-12-18 04:05:50 +01:00
println! ( " \n \n =========RESULT========= \n {} / {} " , count , fs ::read_dir ( & args [ 2 ] ) . unwrap ( ) . count ( ) ) ;
2022-12-15 21:53:01 +01:00
}
2022-11-29 02:04:01 +01:00
" -c " | " --compile " = >
{
let file_content = fs ::read_to_string ( & args [ 2 ] ) . expect ( " Could not read the source file " ) ;
2023-01-23 05:28:13 +01:00
match compile ( & file_content , & args [ 2 ] , & intrinsics , interpret , run , debug )
2022-12-15 21:53:01 +01:00
{
2022-12-18 04:05:50 +01:00
Ok ( maybe_msg ) = >
{
if let Some ( msg ) = maybe_msg
{
print! ( " ---Output--- \n \n {} " , msg ) ;
}
}
2022-12-15 21:53:01 +01:00
Err ( msg ) = > println! ( " ERROR: {} " , msg ) ,
2022-12-14 09:34:41 +01:00
}
2022-11-29 02:04:01 +01:00
}
2022-12-05 00:38:20 +01:00
_ = > panic! ( " Unknown option {} " , args [ 1 ] )
2022-11-29 02:04:01 +01:00
}
}
2023-12-22 22:13:17 +01:00
fn compile ( file_content : & str , file_path : & str , intrinsics : & HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > , interpret : bool , run : bool , debug : bool ) -> Result < Option < String > , String >
2022-12-15 21:53:01 +01:00
{
2023-12-22 22:13:17 +01:00
let mut tokens : Vec < Token > = tokenize ( file_content ) ? ;
2022-12-15 21:53:01 +01:00
println! ( " ---Done tokenizing, got {} tokens--- " , tokens . len ( ) ) ;
2023-02-06 15:00:37 +01:00
let mut functions : Vec < Function > = Vec ::new ( ) ;
2023-12-22 22:13:17 +01:00
extract_functions ( & mut tokens , & mut functions , intrinsics , debug ) ? ;
2022-12-15 21:53:01 +01:00
println! ( " ---Done extracting functions, got {} functions and reduced the token count to {} --- " , functions . len ( ) , tokens . len ( ) ) ;
2023-02-06 15:00:37 +01:00
resolve_imports ( & mut tokens , & mut functions , file_path , & mut Vec ::from ( [ fs ::canonicalize ( file_path ) . unwrap ( ) ] ) , intrinsics , debug ) ? ;
2023-01-23 05:28:13 +01:00
println! ( " ---Done importing files--- " ) ;
2023-12-22 22:13:17 +01:00
let mut arrays : Vec < Arr > = extract_arrays ( & mut tokens , intrinsics , & functions , debug ) ? ;
2022-12-21 21:48:52 +01:00
println! ( " ---Done extracting arrays, got {} arrays and reduced the token count to {} --- " , arrays . len ( ) , tokens . len ( ) ) ;
2023-12-22 22:13:17 +01:00
let operations = parse_until_delimiter ( & mut tokens . iter ( ) . peekable ( ) , intrinsics , None , debug ) ? ;
2022-12-15 21:53:01 +01:00
println! ( " ---Done parsing tokens into {} operations--- " , operations . len ( ) ) ;
2023-12-22 22:13:17 +01:00
validate_function_calls ( & operations , & functions , debug ) ? ;
2022-12-15 21:53:01 +01:00
println! ( " ---Done validating function calls--- " ) ;
2023-12-22 22:13:17 +01:00
typecheck ( & operations , & functions , intrinsics , & arrays , debug ) ? ;
2022-12-15 21:53:01 +01:00
println! ( " ---Done typechecking--- " ) ;
2023-01-09 12:23:01 +01:00
let start = Instant ::now ( ) ;
2022-12-18 04:05:50 +01:00
let output = if interpret
2022-12-15 21:53:01 +01:00
{
2023-01-09 12:35:48 +01:00
println! ( " ---Starting to interpret the program--- " ) ;
2023-12-22 22:13:17 +01:00
Some ( interpret_program ( & operations , & mut Vec ::new ( ) , & functions , & mut arrays , debug ) ? )
2022-12-15 21:53:01 +01:00
}
2022-12-18 04:05:50 +01:00
else
{
None
} ;
2022-12-23 14:49:09 +01:00
if ! interpret
{
2023-12-22 22:13:17 +01:00
if let Err ( err ) = generate_assembly_linux_x64 ( & operations , & functions , & arrays )
2022-12-23 14:49:09 +01:00
{
2023-01-05 00:19:29 +01:00
return Err ( err . to_string ( ) ) ;
2022-12-23 14:49:09 +01:00
}
2023-01-05 00:19:29 +01:00
let mut fasm_process = match Command ::new ( " fasm " ) . arg ( " out.asm " ) . spawn ( )
{
Ok ( process ) = > process ,
2023-12-22 22:13:17 +01:00
Err ( err ) = > return Err ( format! ( " Fasm process error: {} " , err ) ) ,
2023-01-05 00:19:29 +01:00
} ;
match fasm_process . wait ( )
{
Ok ( status ) = >
{
if ! status . success ( )
{
return Err ( format! ( " fasm exited with an error: {} " , status ) ) ;
}
}
Err ( err ) = > return Err ( err . to_string ( ) ) ,
}
}
if run
{
let process = match Command ::new ( " ./out " ) . stdout ( Stdio ::piped ( ) ) . stderr ( Stdio ::piped ( ) ) . spawn ( )
{
Ok ( process ) = > process ,
Err ( err ) = > return Err ( err . to_string ( ) ) ,
} ;
return match process . wait_with_output ( )
{
Ok ( output ) = >
{
match String ::from_utf8 ( output . stdout )
{
Ok ( stdout ) = >
{
match String ::from_utf8 ( output . stderr )
{
Ok ( stderr ) = >
{
2023-01-11 02:33:30 +01:00
let text = format! ( " {} {} " , stdout , stderr ) ;
match output . status . code ( )
{
Some ( 0 ) = > Ok ( Some ( text ) ) ,
_ = > Err ( text ) ,
}
2023-01-05 00:19:29 +01:00
}
Err ( err ) = > Err ( err . to_string ( ) ) ,
}
}
Err ( err ) = > Err ( err . to_string ( ) ) ,
}
}
Err ( err ) = > Err ( err . to_string ( ) ) ,
} ;
2022-12-23 14:49:09 +01:00
}
2023-01-09 12:35:48 +01:00
println! ( " ---Done after {:?} --- " , start . elapsed ( ) ) ;
2023-12-22 22:13:17 +01:00
Ok ( output )
2022-12-15 21:53:01 +01:00
}
2023-01-23 05:28:13 +01:00
fn resolve_imports ( tokens : & mut Vec < Token > , functions : & mut Vec < Function > , file_path : & str , visited_paths : & mut Vec < PathBuf > , intrinsics : & HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > , debug : bool ) -> Result < ( ) , String >
{
let mut tokens_iter = tokens . iter ( ) ;
let mut new_tokens : Vec < Token > = Vec ::new ( ) ;
while let Some ( token ) = tokens_iter . next ( )
{
if let Token ::Import ( line , col ) = token
{
if let Some ( Token ::StringLit ( import_path , _ , _ ) ) = tokens_iter . next ( )
{
2023-12-22 22:13:17 +01:00
println! ( " Resolving {} " , import_path ) ;
2023-02-06 16:03:48 +01:00
let full_import_path = fs ::canonicalize ( file_path ) . map_err ( | e | e . to_string ( ) ) ? . parent ( ) . unwrap ( ) . join ( import_path ) ;
if visited_paths . contains ( & full_import_path )
2023-01-23 05:28:13 +01:00
{
2023-02-06 16:03:48 +01:00
println! ( " --Already visited {} -- " , full_import_path . display ( ) ) ;
}
else
{
visited_paths . push ( full_import_path . clone ( ) ) ;
let maybe_file_content = fs ::read_to_string ( full_import_path ) ;
match maybe_file_content
2023-01-23 05:28:13 +01:00
{
2023-02-06 16:03:48 +01:00
Ok ( file_content ) = >
2023-01-23 05:28:13 +01:00
{
2023-02-06 16:03:48 +01:00
let mut import_tokens : Vec < Token > = tokenize ( & file_content ) ? ;
println! ( " --Done tokenizing the imported file at {} : {} , got {} tokens-- " , line , col , tokens . len ( ) ) ;
2023-12-22 22:13:17 +01:00
extract_functions ( & mut import_tokens , functions , intrinsics , debug ) ? ;
2023-02-06 16:03:48 +01:00
resolve_imports ( & mut import_tokens , functions , file_path , visited_paths , intrinsics , debug ) ? ;
println! ( " --Now totalling {} functions-- " , functions . len ( ) ) ;
2023-01-23 05:28:13 +01:00
}
2023-02-06 16:03:48 +01:00
Err ( e ) = > return Err ( e . to_string ( ) ) ,
2023-01-23 05:28:13 +01:00
}
}
}
else
{
return Err ( format! ( " Expected an import location at {} : {} " , line , col ) ) ;
}
}
else
{
new_tokens . push ( token . clone ( ) ) ;
}
}
tokens . clear ( ) ;
tokens . extend_from_slice ( & new_tokens ) ;
2023-12-22 22:13:17 +01:00
Ok ( ( ) )
2023-01-23 05:28:13 +01:00
}
2022-12-23 14:49:09 +01:00
struct AssemblyData
{
strings : String ,
code : String ,
arrays : String ,
}
fn merge_assemblies ( data : & mut AssemblyData , data2 : AssemblyData )
{
data . arrays + = data2 . arrays . as_str ( ) ;
data . code + = data2 . code . as_str ( ) ;
data . strings + = data2 . strings . as_str ( ) ;
}
2023-07-28 07:04:39 +02:00
const ASSEMBLY_LINUX_X64_QUEUE_LENGTH : u32 = 8192 ;
2022-12-23 14:49:09 +01:00
const ASSEMBLY_LINUX_X64_HEADER : & str = " format ELF64 executable 3 \n " ;
2023-01-03 20:39:08 +01:00
const ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE : & str = " \t cmp r12, r13 \n \t cmove r12, r14 \n \t cmove r13, r14 \n " ;
2022-12-23 14:49:09 +01:00
const ASSEMBLY_LINUX_X64_EXIT : & str = " \t mov rax, 60 \n \t mov rdi, 0 \n \t syscall \n " ;
2023-01-03 17:07:57 +01:00
const ASSEMBLY_LINUX_X64_DYNAMIC_DATA_LENGTH : u32 = 16384 ;
2022-12-23 14:49:09 +01:00
2023-01-04 00:45:34 +01:00
// r12: head
// r13: tail
// r14: base
// r15: dynamic end
2023-12-22 22:13:17 +01:00
fn generate_assembly_linux_x64 ( operations : & Vec < Operation > , functions : & Vec < Function > , arrays : & Vec < Arr > ) -> Result < ( ) , std ::io ::Error >
2022-12-23 14:49:09 +01:00
{
let mut data = AssemblyData
{
2023-01-03 17:07:57 +01:00
arrays : format ! ( " segment readable writeable \n \t queue: rq {} \n \t dynamic: rb {} \n " , ASSEMBLY_LINUX_X64_QUEUE_LENGTH , ASSEMBLY_LINUX_X64_DYNAMIC_DATA_LENGTH ) ,
2023-01-03 20:39:08 +01:00
strings : String ::from ( " segment readable \n \t newline: db 10 \n " ) ,
2022-12-23 14:49:09 +01:00
code : String ::from ( " segment executable \n " ) ,
} ;
for array in arrays
{
data . arrays + = format! ( " \t arr_ {} : rq {} \n " , array . name , array . length ) . as_str ( ) ;
}
2023-01-03 20:39:08 +01:00
data . code + = " _start: \n " ;
2023-12-22 22:13:17 +01:00
merge_assemblies ( & mut data , generate_assembly_linux_x64_block ( operations , functions , arrays ) ) ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_EXIT ;
2022-12-23 14:49:09 +01:00
for function in functions
{
2023-12-22 22:13:17 +01:00
merge_assemblies ( & mut data , generate_assembly_linux_x64_function ( function . name . as_str ( ) , & function . content , functions , arrays ) ) ;
2022-12-23 14:49:09 +01:00
}
2023-01-03 17:07:57 +01:00
if data . code . contains ( " call intToStr " )
{
data . code + = " intToStr: \n " ;
data . code + = " \t mov rax, rdi \n " ;
data . code + = " \t mov rsi, 10 \n " ;
data . code + = " \t xor rdi, rdi \n " ;
2023-01-03 20:39:08 +01:00
data . code + = " \t xor rdx, rdx \n " ;
2023-01-03 17:07:57 +01:00
data . code + = " \t intToStringLoop: \n " ;
data . code + = " \t \t div rsi \n " ;
data . code + = " \t \t add rdx, 48 \n " ;
data . code + = " \t \t push rdx \n " ;
data . code + = " \t \t xor rdx, rdx \n " ;
data . code + = " \t \t inc rdi \n " ;
data . code + = " \t \t cmp rax, 0 \n " ;
data . code + = " \t \t jne intToStringLoop \n " ;
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rsi, r15 \n " ;
data . code + = " \t mov qword [dynamic+r15], rdi \n " ;
data . code + = " \t add r15, 8 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = " \t intToStringBuildLoop: \n " ;
data . code + = " \t \t cmp rdi, 0 \n " ;
data . code + = " \t \t je intToStringBuildLoopEnd \n " ;
data . code + = " \t \t pop rax \n " ;
2023-01-03 20:39:08 +01:00
data . code + = " \t \t mov byte [dynamic+r15], byte al \n " ;
data . code + = " \t \t inc r15 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = " \t \t dec rdi \n " ;
data . code + = " \t \t jmp intToStringBuildLoop \n " ;
data . code + = " \t intToStringBuildLoopEnd: \n " ;
2023-01-03 20:39:08 +01:00
data . code + = " \t mov byte [dynamic+r15], 0 \n " ;
data . code + = " \t inc r15 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = " \t lea rax, [dynamic+rsi] \n " ;
data . code + = " \t ret \n " ;
}
2023-01-11 02:33:30 +01:00
if data . code . contains ( " exception_array_read_out_of_bounds " )
{
data . strings + = " \t exception_array_oob_msg db \" Attempted array out-of-bounds access \" , 10 \n " ;
data . code + = " exception_array_read_out_of_bounds: \n " ;
//TODO: report the passed sizes
data . code + = " \t mov rax, 1 \n " ;
2023-01-11 19:45:38 +01:00
data . code + = " \t mov rdi, 2 \n " ;
2023-01-11 02:33:30 +01:00
// size
data . code + = " \t mov rdx, 37 \n " ;
// data
data . code + = " \t mov rsi, exception_array_oob_msg \n " ;
data . code + = " \t syscall \n " ;
data . code + = " \t mov rax, 60 \n " ;
data . code + = " \t mov rdi, -1 \n " ;
data . code + = " \t syscall \n " ;
}
2023-07-28 04:55:08 +02:00
if data . code . contains ( " exception_queue_read_out_of_bounds " )
{
data . strings + = " \t exception_queue_oob_msg db \" Queue overflow \" , 10 \n " ;
data . code + = " exception_queue_read_out_of_bounds: \n " ;
//TODO: report the passed sizes
data . code + = " \t mov rax, 1 \n " ;
data . code + = " \t mov rdi, 2 \n " ;
// size
data . code + = " \t mov rdx, 37 \n " ;
// data
data . code + = " \t mov rsi, exception_queue_oob_msg \n " ;
data . code + = " \t syscall \n " ;
data . code + = " \t mov rax, 60 \n " ;
data . code + = " \t mov rdi, -1 \n " ;
data . code + = " \t syscall \n " ;
}
2022-12-23 14:49:09 +01:00
2023-12-22 22:13:17 +01:00
fs ::write ( " out.asm " , format! ( " {} {} {} {} " , ASSEMBLY_LINUX_X64_HEADER , data . code , data . arrays , data . strings ) )
2022-12-23 14:49:09 +01:00
}
2023-01-11 02:33:30 +01:00
fn generate_assembly_linux_x64_array_oob_check ( length : i64 ) -> String
{
let mut data = String ::new ( ) ;
data + = " \t \t ;;Array bounds check \n " ;
data + = format! ( " \t cmp qword rax, {} \n " , length ) . as_str ( ) ;
data + = " \t jge exception_array_read_out_of_bounds \n " ;
data + = " \t cmp qword rax, 0 \n " ;
data + = " \t jl exception_array_read_out_of_bounds \n " ;
data + = " \t \t ;;Array bounds check over \n " ;
2023-12-22 22:13:17 +01:00
data . clone ( )
2023-01-11 02:33:30 +01:00
}
2023-07-28 04:55:08 +02:00
fn generate_assembly_linux_x64_queue_oob_check ( ) -> String
{
return " \t \t ;;Queue bounds check \n " . to_string ( ) +
format! ( " \t cmp qword r13, {} \n " , ASSEMBLY_LINUX_X64_QUEUE_LENGTH ) . as_str ( ) +
" \t jge exception_queue_read_out_of_bounds \n \t \t ;;Queue bounds over \n " ;
}
2023-12-22 22:13:17 +01:00
fn generate_assembly_linux_x64_block ( operations : & Vec < Operation > , functions : & Vec < Function > , arrays : & Vec < Arr > ) -> AssemblyData
2022-12-23 14:49:09 +01:00
{
let mut data = AssemblyData
{
arrays : String ::new ( ) ,
code : String ::new ( ) ,
strings : String ::new ( ) ,
} ;
for operation in operations
{
match operation
{
Operation ::Dequeue ( line , col ) = >
{
data . code + = format! ( " \t ;;deq {} : {} \n " , line , col ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r12 \n " ;
2022-12-23 14:49:09 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
}
Operation ::Enqueue ( datatype , value , line , col ) = >
{
data . code + = format! ( " \t ;;enq {:?} {} {} : {} \n " , datatype , value , line , col ) . as_str ( ) ;
match datatype
{
2023-01-03 17:07:57 +01:00
Datatype ::Int = >
{
2023-01-03 20:39:08 +01:00
data . code + = format! ( " \t mov qword [queue+8*r13], {} \n " , value ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
Datatype ::Bool = >
{
2023-01-03 20:39:08 +01:00
data . code + = format! ( " \t mov qword [queue+8*r13], {} \n " , if value = = " true " { 1 } else { 0 } ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
Datatype ::String = >
2022-12-23 14:49:09 +01:00
{
2023-01-23 05:28:13 +01:00
data . strings + = format! ( " \t str_ {} _ {} : db {} , {} , {} , {} , {} , {} , {} , {} , \" {} \" , 0 \n " ,
2023-01-05 00:19:29 +01:00
line , col ,
value . len ( ) % 256 ,
( value . len ( ) > > 8 ) % 256 ,
( value . len ( ) > > 16 ) % 256 ,
( value . len ( ) > > 24 ) % 256 ,
( value . len ( ) > > 32 ) % 256 ,
( value . len ( ) > > 40 ) % 256 ,
( value . len ( ) > > 48 ) % 256 ,
( value . len ( ) > > 56 ) % 256 ,
value ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
data . code + = format! ( " \t lea rax, [str_ {} _ {} ] \n " , line , col ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t mov [queue+8*r13], rax \n " ;
2022-12-23 14:49:09 +01:00
}
}
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
Operation ::Requeue ( line , col ) = >
{
data . code + = format! ( " \t ;;req {} : {} \n " , line , col ) . as_str ( ) ;
2023-07-28 07:04:39 +02:00
data . code + = " \t mov rax, r13 \n " ;
data . code + = " \t sub rax, r12 \n " ;
data . code + = " \t cmp rax, 2 \n " ;
data . code + = format! ( " \t je req_ {line} _ {col} _special \n " ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t inc r12 \n " ;
2023-01-04 00:45:34 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t mov [queue+8*r13], rax \n " ;
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-07-28 07:04:39 +02:00
data . code + = format! ( " \t jmp req_ {line} _ {col} _end \n " ) . as_str ( ) ;
data . code + = format! ( " req_ {line} _ {col} _special: \n " ) . as_str ( ) ;
data . code + = " \t mov qword rax, [queue+8*r12] \n " ;
data . code + = " \t mov qword rdi, [queue+8*r12+8] \n " ;
data . code + = " \t mov qword r12, r14 \n " ;
data . code + = " \t mov qword r13, r14 \n " ;
data . code + = " \t mov qword [queue+8*r12], rdi \n " ;
data . code + = " \t mov qword [queue+8*r12+8], rax \n " ;
data . code + = " \t add r13, 2 \n " ;
data . code + = format! ( " req_ {line} _ {col} _end: \n " ) . as_str ( ) ;
2022-12-23 14:49:09 +01:00
}
2023-01-03 21:52:48 +01:00
Operation ::Swap ( line , col ) = >
{
data . code + = format! ( " \t ;;swp {} : {} \n " , line , col ) . as_str ( ) ;
2023-07-28 07:04:39 +02:00
data . code + = " \t mov rax, r13 \n " ;
data . code + = " \t sub rax, r12 \n " ;
data . code + = " \t cmp rax, 2 \n " ;
data . code + = format! ( " \t je swp_ {line} _ {col} _special \n " ) . as_str ( ) ;
2023-01-03 21:52:48 +01:00
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t mov rbx, [queue+8*r12+8] \n " ;
data . code + = " \t add r12, 2 \n " ;
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t mov [queue+8*r13], rbx \n " ;
data . code + = " \t mov [queue+8*r13+8], rax \n " ;
data . code + = " \t add r13, 2 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-07-28 07:04:39 +02:00
data . code + = format! ( " \t jmp swp_ {line} _ {col} _end \n " ) . as_str ( ) ;
data . code + = format! ( " swp_ {line} _ {col} _special: \n " ) . as_str ( ) ;
data . code + = " \t mov qword rax, [queue+8*r12] \n " ;
data . code + = " \t mov qword rdi, [queue+8*r12+8] \n " ;
data . code + = " \t mov qword r12, r14 \n " ;
data . code + = " \t mov qword r13, r14 \n " ;
data . code + = " \t mov qword [queue+8*r12], rdi \n " ;
data . code + = " \t mov qword [queue+8*r12+8], rax \n " ;
data . code + = " \t add r13, 2 \n " ;
data . code + = format! ( " swp_ {line} _ {col} _end: \n " ) . as_str ( ) ;
2023-01-03 21:52:48 +01:00
}
2022-12-23 14:49:09 +01:00
Operation ::While ( while_operations , line , col ) = >
{
data . code + = format! ( " \t ;;while {} : {} \n " , line , col ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t cmp qword [queue+8*r12], 0 \n " ;
2022-12-23 14:49:09 +01:00
data . code + = format! ( " \t je while_ {} _ {} _end \n " , line , col ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = format! ( " while_ {} _ {} : \n " , line , col ) . as_str ( ) ;
data . code + = " \t inc r12 \n " ;
2022-12-23 14:49:09 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
2023-12-22 22:13:17 +01:00
merge_assemblies ( & mut data , generate_assembly_linux_x64_block ( while_operations , functions , arrays ) ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t cmp qword [queue+8*r12], 0 \n " ;
data . code + = format! ( " \t jne while_ {} _ {} \n " , line , col ) . as_str ( ) ;
2022-12-23 14:49:09 +01:00
data . code + = format! ( " while_ {} _ {} _end: \n " , line , col ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r12 \n " ;
2022-12-23 14:49:09 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
}
2023-01-03 17:07:57 +01:00
Operation ::If ( if_operations , maybe_else_operations , line , col ) = >
{
data . code + = format! ( " \t ;;if {} : {} \n " , line , col ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t cmp qword [queue+8*r12], 0 \n " ;
data . code + = format! ( " \t je else_ {} _ {} \n " , line , col ) . as_str ( ) ;
data . code + = " \t inc r12 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
2023-12-22 22:13:17 +01:00
merge_assemblies ( & mut data , generate_assembly_linux_x64_block ( if_operations , functions , arrays ) ) ;
2023-01-03 17:07:57 +01:00
data . code + = format! ( " \t jmp if_ {} _ {} _end \n " , line , col ) . as_str ( ) ;
data . code + = format! ( " else_ {} _ {} : \n " , line , col ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r12 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
if let Some ( else_operations ) = maybe_else_operations
{
2023-12-22 22:13:17 +01:00
merge_assemblies ( & mut data , generate_assembly_linux_x64_block ( else_operations , functions , arrays ) ) ;
2023-01-03 17:07:57 +01:00
}
data . code + = format! ( " if_ {} _ {} _end: \n " , line , col ) . as_str ( ) ;
}
2022-12-23 14:49:09 +01:00
Operation ::Dup ( line , col ) = >
{
data . code + = format! ( " \t ;;dup {} : {} \n " , line , col ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t mov [queue+8*r13], rax \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2022-12-23 14:49:09 +01:00
}
Operation ::Intrinsic ( name , line , col ) = >
{
2023-01-03 17:07:57 +01:00
data . code + = format! ( " \t ;;intrinsic {} {} : {} \n " , name , line , col ) . as_str ( ) ;
2022-12-23 14:49:09 +01:00
match name . as_str ( )
{
" print " = >
{
// For now printing numbers directly is unsupported
2023-01-03 17:07:57 +01:00
data . code + = " \t mov rax, 1 \n " ;
data . code + = " \t mov rdi, 1 \n " ;
// load address
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rsi, [queue+8*r12] \n " ;
2023-01-03 17:07:57 +01:00
// size
data . code + = " \t mov rdx, [rsi] \n " ;
// data
data . code + = " \t lea rsi, [rsi+8] \n " ;
// incorporate the null byte
2023-01-05 00:19:29 +01:00
//data.code += "\tinc rdx\n";
2023-01-03 17:07:57 +01:00
data . code + = " \t syscall \n " ;
// TODO: factor this out
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r12 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
}
" println " = >
{
// For now printing numbers directly is unsupported
data . code + = " \t mov rax, 1 \n " ;
data . code + = " \t mov rdi, 1 \n " ;
// load address
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rsi, [queue+8*r12] \n " ;
2023-01-03 17:07:57 +01:00
// size
data . code + = " \t mov rdx, [rsi] \n " ;
// data
data . code + = " \t lea rsi, [rsi+8] \n " ;
// incorporate the null byte
2023-01-05 00:19:29 +01:00
//data.code += "\tinc rdx\n";
2023-01-03 17:07:57 +01:00
data . code + = " \t syscall \n " ;
// TODO: factor this out
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r12 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
// TODO: Don't syscall twice
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rax, 1 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = " \t lea rsi, [newline] \n " ;
data . code + = " \t mov rdx, 1 \n " ;
data . code + = " \t syscall \n " ;
}
" intToStr " = >
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov qword rdi, [queue+8*r12] \n " ;
2023-01-03 17:07:57 +01:00
data . code + = " \t inc r12 \n " ;
2023-01-03 20:44:07 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
2023-01-03 20:39:08 +01:00
data . code + = " \t call intToStr \n " ;
data . code + = " \t mov [queue+8*r13], rax \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
" - " = >
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov qword rax, [queue+8*r12] \n " ;
data . code + = " \t inc r12 \n " ;
data . code + = " \t mov qword rbx, [queue+8*r12] \n " ;
data . code + = " \t inc r12 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t sub rax, rbx \n " ;
2023-01-03 20:39:08 +01:00
data . code + = " \t mov [queue+8*r13], rax \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
2023-01-03 21:52:48 +01:00
" + " = >
{
data . code + = " \t mov qword rax, [queue+8*r12] \n " ;
data . code + = " \t inc r12 \n " ;
data . code + = " \t mov qword rbx, [queue+8*r12] \n " ;
data . code + = " \t inc r12 \n " ;
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t add rax, rbx \n " ;
data . code + = " \t mov [queue+8*r13], rax \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 21:52:48 +01:00
}
" * " = >
{
data . code + = " \t mov qword rax, [queue+8*r12] \n " ;
data . code + = " \t inc r12 \n " ;
data . code + = " \t mov qword rbx, [queue+8*r12] \n " ;
data . code + = " \t inc r12 \n " ;
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t mul rbx \n " ;
data . code + = " \t mov [queue+8*r13], rax \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 21:52:48 +01:00
}
2023-07-28 03:01:13 +02:00
" divmod " = >
{
data . code + = " \t mov qword rax, [queue+8*r12] \n " ;
data . code + = " \t mov qword rdx, 0 \n " ;
data . code + = " \t inc r12 \n " ;
data . code + = " \t mov qword rbx, [queue+8*r12] \n " ;
data . code + = " \t inc r12 \n " ;
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t idiv rbx \n " ;
data . code + = " \t mov [queue+8*r13], rax \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-07-28 03:01:13 +02:00
data . code + = " \t mov [queue+8*r13], rdx \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-07-28 03:01:13 +02:00
}
2023-01-03 17:07:57 +01:00
" > " = >
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rbx, 0 \n " ;
data . code + = " \t mov rcx, 1 \n " ;
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t cmp qword rax, [queue+8*r12+8] \n " ;
data . code + = " \t cmovg rbx, rcx \n " ;
data . code + = " \t add r12, 2 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
2023-01-03 20:55:05 +01:00
data . code + = " \t mov qword [queue+8*r13], rbx \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
" < " = >
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rbx, 0 \n " ;
data . code + = " \t mov rcx, 1 \n " ;
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t cmp qword rax, [queue+8*r12+8] \n " ;
data . code + = " \t cmovl rbx, rcx \n " ;
data . code + = " \t add r12, 2 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
2023-01-03 20:55:05 +01:00
data . code + = " \t mov qword [queue+8*r13], rbx \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
" >= " = >
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rbx, 0 \n " ;
data . code + = " \t mov rcx, 1 \n " ;
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t cmp qword rax, [queue+8*r12+8] \n " ;
data . code + = " \t cmovge rbx, rcx \n " ;
data . code + = " \t add r12, 2 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
2023-01-03 20:55:05 +01:00
data . code + = " \t mov qword [queue+8*r13], rbx \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
" <= " = >
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rbx, 0 \n " ;
data . code + = " \t mov rcx, 1 \n " ;
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t cmp qword rax, [queue+8*r12+8] \n " ;
data . code + = " \t cmovle rbx, rcx \n " ;
data . code + = " \t add r12, 2 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
2023-01-03 20:55:05 +01:00
data . code + = " \t mov qword [queue+8*r13], rbx \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2022-12-23 14:49:09 +01:00
}
2023-01-03 21:52:48 +01:00
" == " = >
{
data . code + = " \t mov rbx, 0 \n " ;
data . code + = " \t mov rcx, 1 \n " ;
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t cmp qword rax, [queue+8*r12+8] \n " ;
data . code + = " \t cmove rbx, rcx \n " ;
data . code + = " \t add r12, 2 \n " ;
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t mov qword [queue+8*r13], rbx \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 21:52:48 +01:00
}
2023-07-28 03:01:13 +02:00
" != " = >
{
data . code + = " \t mov rbx, 0 \n " ;
data . code + = " \t mov rcx, 1 \n " ;
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t cmp qword rax, [queue+8*r12+8] \n " ;
data . code + = " \t cmovne rbx, rcx \n " ;
data . code + = " \t add r12, 2 \n " ;
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t mov qword [queue+8*r13], rbx \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-07-28 03:01:13 +02:00
}
2023-01-03 21:52:48 +01:00
" && " = >
{
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t mov rbx, [queue+8*r12+8] \n " ;
data . code + = " \t and rax, rbx \n " ;
data . code + = " \t add r12, 2 \n " ;
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t mov [queue+8*r13], rax \n " ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 21:52:48 +01:00
}
2022-12-23 14:49:09 +01:00
_ = > todo! ( " intrinsic {} {} : {} " , name , line , col )
}
}
2023-01-03 17:07:57 +01:00
Operation ::Apply ( name , word , line , col ) = >
{
2023-01-11 02:33:30 +01:00
let array = arrays . iter ( ) . find ( | x | & x . name = = name ) . unwrap ( ) ;
2023-01-03 17:07:57 +01:00
data . code + = format! ( " \t ;;apply {} . {} {} : {} \n " , name , word , line , col ) . as_str ( ) ;
match word . as_str ( )
{
" read " = >
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rax, [queue+8*r12] \n " ;
2023-01-11 02:33:30 +01:00
data . code + = generate_assembly_linux_x64_array_oob_check ( array . length ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
data . code + = " \t inc r12 \n " ;
2023-01-03 20:39:08 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
2023-01-03 21:52:48 +01:00
data . code + = format! ( " \t mov qword rbx, [arr_ {} +8*rax] \n " , name ) . as_str ( ) ;
data . code + = " \t mov qword [queue+8*r13], rbx \n " ;
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
" write " = >
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rax, [queue+8*r12] \n " ;
2023-01-11 02:33:30 +01:00
data . code + = generate_assembly_linux_x64_array_oob_check ( array . length ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r12 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
2023-01-03 21:52:48 +01:00
data . code + = " \t mov qword rbx, [queue+8*r12] \n " ;
data . code + = format! ( " \t mov qword [arr_ {} +8*rax], rbx \n " , name ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r12 \n " ;
2023-01-03 17:07:57 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
}
2023-01-03 21:52:48 +01:00
" length " = >
{
data . code + = format! ( " \t mov qword [queue+8*r13], {} \n " , array . length ) . as_str ( ) ;
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 21:52:48 +01:00
}
2023-01-03 17:07:57 +01:00
_ = > todo! ( " apply {} " , word )
}
}
Operation ::FunctionCall ( name , line , col ) = >
{
data . code + = format! ( " \t ;;func call {} {} : {} \n " , name , line , col ) . as_str ( ) ;
let function = functions . iter ( ) . find ( | x | & x . name = = name ) . unwrap ( ) ;
for _ in 0 .. function . ins . len ( )
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rax, [queue+8*r12] \n " ;
2023-01-03 17:07:57 +01:00
data . code + = " \t inc r12 \n " ;
2023-01-04 00:45:34 +01:00
data . code + = ASSEMBLY_LINUX_X64_TRY_RESET_QUEUE ;
data . code + = " \t mov [queue+8*r13], rax \n " ;
2023-01-03 20:39:08 +01:00
data . code + = " \t inc r13 \n " ;
2023-07-28 04:55:08 +02:00
data . code + = generate_assembly_linux_x64_queue_oob_check ( ) . as_str ( ) ;
2023-01-03 17:07:57 +01:00
}
data . code + = " \t ;; move pointers \n " ;
// save the current base
2023-01-03 20:39:08 +01:00
data . code + = " \t push r14 \n " ;
2023-01-03 17:07:57 +01:00
// save the current head
2023-01-03 20:39:08 +01:00
data . code + = " \t push r12 \n " ;
2023-01-03 17:07:57 +01:00
// prepare the layout
2023-01-03 20:39:08 +01:00
data . code + = " \t mov r14, r13 \n " ;
data . code + = format! ( " \t sub r14, {} \n " , function . ins . len ( ) ) . as_str ( ) ;
data . code + = " \t mov r12, r14 \n " ;
2023-01-03 17:07:57 +01:00
// call
data . code + = format! ( " \t call {} \n " , name ) . as_str ( ) ;
// move the sub-queue back to the base
for _ in 0 .. function . outs . len ( )
{
2023-01-03 20:39:08 +01:00
data . code + = " \t mov rax, [queue+8*r12] \n " ;
data . code + = " \t mov [queue+8*r14], rax \n " ;
data . code + = " \t inc r12 \n " ;
data . code + = " \t inc r14 \n " ;
2023-01-03 17:07:57 +01:00
}
// restore the tail
2023-01-03 20:39:08 +01:00
data . code + = " \t mov r13, r14 \n " ;
2023-01-03 17:07:57 +01:00
// restore the head
2023-01-03 20:39:08 +01:00
data . code + = " \t pop r12 \n " ;
// restore the base
data . code + = " \t pop r14 \n " ;
}
Operation ::Interrupt ( line , col ) = >
{
2023-01-03 20:44:07 +01:00
data . code + = format! ( " \t ;;interrupt {} : {} \n " , line , col ) . as_str ( ) ;
2023-01-03 20:39:08 +01:00
data . code + = " lea r8, [queue] \n " ;
data . code + = format! ( " mov r9, {} \n " , 1000 * line + col ) . as_str ( ) ;
data . code + = " int3 \n " ;
2023-01-03 17:07:57 +01:00
}
2022-12-23 14:49:09 +01:00
_ = > todo! ( " {:?} " , operation )
}
}
2023-12-22 22:13:17 +01:00
data
2022-12-23 14:49:09 +01:00
}
2023-12-22 22:13:17 +01:00
fn generate_assembly_linux_x64_function ( name : & str , operations : & Vec < Operation > , functions : & Vec < Function > , arrays : & Vec < Arr > ) -> AssemblyData
2022-12-23 14:49:09 +01:00
{
let mut data = AssemblyData
{
arrays : String ::new ( ) ,
code : format ! ( " {}: \n " , name ) ,
strings : String ::new ( ) ,
} ;
2023-12-22 22:13:17 +01:00
merge_assemblies ( & mut data , generate_assembly_linux_x64_block ( operations , functions , arrays ) ) ;
2023-01-03 17:07:57 +01:00
data . code + = " \t ret \n " ;
2023-12-22 22:13:17 +01:00
data
2022-12-23 14:49:09 +01:00
}
2023-12-22 22:13:17 +01:00
fn interpret_program ( operations : & Vec < Operation > , queue : & mut Vec < String > , functions : & Vec < Function > , arrays : & mut Vec < Arr > , debug : bool ) -> Result < String , String >
2022-12-14 09:34:41 +01:00
{
2022-12-18 04:05:50 +01:00
let mut output = String ::new ( ) ;
2022-12-14 09:34:41 +01:00
for operation in operations
{
if debug
{
2022-12-18 04:05:50 +01:00
println! ( " before: {:?} : {:?} , ' {} ' " , operation , queue , output ) ;
2022-12-14 09:34:41 +01:00
}
match operation
{
Operation ::Dequeue ( _ , _ ) = >
{
queue . remove ( 0 ) ;
}
Operation ::Enqueue ( _ , value , _ , _ ) = >
{
queue . push ( value . clone ( ) ) ;
}
Operation ::Requeue ( _ , _ ) = >
{
let val = queue . remove ( 0 ) ;
queue . push ( val ) ;
}
2022-12-14 11:46:39 +01:00
Operation ::Dup ( _ , _ ) = >
{
let val = queue . get ( 0 ) . unwrap ( ) ;
queue . push ( val . clone ( ) ) ;
}
Operation ::Swap ( _ , _ ) = >
{
let first = queue . remove ( 0 ) ;
let second = queue . remove ( 0 ) ;
queue . push ( second ) ;
queue . push ( first ) ;
}
2022-12-14 09:34:41 +01:00
Operation ::FunctionCall ( function_name , _ , _ ) = >
{
2022-12-15 20:34:56 +01:00
let function = functions . iter ( ) . find ( | x | & x . name = = function_name ) . unwrap ( ) ;
let function_context : & mut Vec < String > = & mut Vec ::new ( ) ;
for _ in 0 .. function . ins . len ( )
{
let val = queue . remove ( 0 ) ;
function_context . push ( val ) ;
}
2023-12-22 22:13:17 +01:00
output + = interpret_program ( & function . content , function_context , functions , arrays , debug ) ? . as_str ( ) ;
2022-12-15 20:34:56 +01:00
for val in function_context
{
queue . push ( val . to_string ( ) ) ;
}
2022-12-14 09:34:41 +01:00
}
Operation ::If ( if_block , maybe_else_block , _ , _ ) = >
{
let val = queue . remove ( 0 ) ;
2022-12-14 20:39:51 +01:00
if val = = " true "
2022-12-14 09:34:41 +01:00
{
2023-12-22 22:13:17 +01:00
output + = interpret_program ( if_block , queue , functions , arrays , debug ) ? . as_str ( ) ;
2022-12-14 09:34:41 +01:00
}
else if let Some ( else_block ) = maybe_else_block
{
2023-12-22 22:13:17 +01:00
output + = interpret_program ( else_block , queue , functions , arrays , debug ) ? . as_str ( ) ;
2022-12-14 09:34:41 +01:00
}
}
Operation ::Intrinsic ( intrinsic_name , line , col ) = >
{
match intrinsic_name . as_str ( )
{
" print " = >
{
2023-12-22 22:13:17 +01:00
output + = queue . remove ( 0 ) . to_string ( ) . as_str ( ) ;
2022-12-14 09:34:41 +01:00
}
" - " = >
{
let minuend = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let subtrahend = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
queue . push ( ( minuend - subtrahend ) . to_string ( ) ) ;
}
2022-12-14 11:46:39 +01:00
" + " = >
{
let addend1 = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let addend2 = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
queue . push ( ( addend1 + addend2 ) . to_string ( ) ) ;
}
2022-12-22 10:29:25 +01:00
" * " = >
{
let multiplicant1 = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let multiplicant2 = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
queue . push ( ( multiplicant1 * multiplicant2 ) . to_string ( ) ) ;
}
2023-07-28 03:01:13 +02:00
" divmod " = >
{
let dividend = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let divisor = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
queue . push ( ( dividend / divisor ) . to_string ( ) ) ;
queue . push ( ( dividend % divisor ) . to_string ( ) ) ;
}
2022-12-14 20:39:51 +01:00
" > " = >
{
let first = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let second = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
queue . push ( ( first > second ) . to_string ( ) ) ;
}
2023-01-03 20:39:08 +01:00
" < " = >
{
let first = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let second = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
queue . push ( ( first < second ) . to_string ( ) ) ;
}
2022-12-22 10:29:25 +01:00
" >= " = >
{
let first = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let second = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
queue . push ( ( first > = second ) . to_string ( ) ) ;
}
2023-01-03 20:39:08 +01:00
" <= " = >
2022-12-14 20:39:51 +01:00
{
let first = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let second = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
2023-01-03 20:39:08 +01:00
queue . push ( ( first < = second ) . to_string ( ) ) ;
2022-12-14 20:39:51 +01:00
}
" == " = >
{
let first = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let second = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
queue . push ( ( first = = second ) . to_string ( ) ) ;
}
" != " = >
{
let first = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
let second = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
queue . push ( ( first ! = second ) . to_string ( ) ) ;
}
2022-12-22 10:29:25 +01:00
" && " = >
{
let first = queue . remove ( 0 ) . parse ::< bool > ( ) . unwrap ( ) ;
let second = queue . remove ( 0 ) . parse ::< bool > ( ) . unwrap ( ) ;
queue . push ( ( first & & second ) . to_string ( ) ) ;
}
2022-12-15 20:34:56 +01:00
" println " = >
{
2022-12-18 04:05:50 +01:00
output + = format! ( " {} \n " , queue . remove ( 0 ) ) . as_str ( ) ;
2022-12-15 20:34:56 +01:00
}
2022-12-31 16:09:55 +01:00
" intToStr " = >
{
let val = queue . remove ( 0 ) . clone ( ) ;
queue . push ( val ) ;
}
2022-12-14 09:34:41 +01:00
_ = >
{
2022-12-22 00:47:41 +01:00
return Err ( format! ( " Unexpected intrinsic ' {} ' at {} : {} " , intrinsic_name , line , col ) ) ;
2022-12-14 09:34:41 +01:00
}
}
}
2022-12-21 21:48:52 +01:00
Operation ::Apply ( name , word , line , col ) = >
{
let arr : & mut Arr = arrays . iter_mut ( ) . find ( | x | & x . name = = name ) . unwrap ( ) ;
match word . as_str ( )
{
" write " = >
{
let position : i64 = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
if position > = arr . length
{
2023-01-11 02:33:30 +01:00
//return Err(format!("Attempted an out of bounds write for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col));
2023-01-23 06:08:26 +01:00
return Err ( String ::from ( " Attempted array out-of-bounds access \n " ) ) ;
2022-12-22 00:47:41 +01:00
}
if position < 0
{
2023-01-11 02:33:30 +01:00
//return Err(format!("Attempted an out of bounds write for array {} ({} < 0) at {}:{}", arr.name, position, line, col));
2023-01-23 06:08:26 +01:00
return Err ( String ::from ( " Attempted array out-of-bounds access \n " ) ) ;
2022-12-21 21:48:52 +01:00
}
2022-12-22 10:29:25 +01:00
let data = queue . remove ( 0 ) ;
if debug
{
println! ( " write before: {} {} {:?} " , position , data , arr ) ;
}
arr . data [ position as usize ] = data ;
if debug
{
println! ( " write after: {:?} " , arr ) ;
}
2022-12-21 21:48:52 +01:00
}
" read " = >
{
let position : i64 = queue . remove ( 0 ) . parse ::< i64 > ( ) . unwrap ( ) ;
if position > = arr . length
{
2023-01-11 02:33:30 +01:00
//return Err(format!("Attempted an out of bounds read for array {} ({} >= {}) at {}:{}", arr.name, position, arr.length, line, col));
2023-01-23 06:08:26 +01:00
return Err ( String ::from ( " Attempted array out-of-bounds access \n " ) ) ;
2022-12-22 00:47:41 +01:00
}
if position < 0
{
2023-01-11 02:33:30 +01:00
//return Err(format!("Attempted an out of bounds read for array {} ({} < 0) at {}:{}", arr.name, position, line, col));
2023-01-23 06:08:26 +01:00
return Err ( String ::from ( " Attempted array out-of-bounds access \n " ) ) ;
2022-12-21 21:48:52 +01:00
}
queue . push ( arr . data [ position as usize ] . clone ( ) ) ;
}
" length " = >
{
queue . push ( arr . length . to_string ( ) ) ;
}
2022-12-22 00:47:41 +01:00
_ = > return Err ( format! ( " Unexpected application ' {} ' at {} : {} " , word , line , col ) )
2022-12-21 21:48:52 +01:00
}
}
2022-12-14 09:34:41 +01:00
Operation ::While ( while_block , _ , _ ) = >
{
loop
{
2022-12-14 11:46:39 +01:00
let val = queue . remove ( 0 ) ;
2022-12-14 20:39:51 +01:00
if val = = " false "
2022-12-14 09:34:41 +01:00
{
break ;
}
2023-12-22 22:13:17 +01:00
output + = interpret_program ( while_block , queue , functions , arrays , debug ) ? . as_str ( ) ;
2022-12-14 09:34:41 +01:00
}
}
2022-12-15 20:34:56 +01:00
Operation ::Depth ( _ , _ ) = >
{
let depth = queue . len ( ) ;
queue . push ( depth . to_string ( ) ) ;
}
Operation ::QueueDiagnostic ( line , col ) = >
{
println! ( " ---Queue state at {} : {} --- \n length: {} \n {:?} \n ------------------------------ " , line , col , queue . len ( ) , queue ) ;
}
2023-01-03 20:39:08 +01:00
Operation ::Interrupt ( _ , _ ) = > { }
2022-12-14 09:34:41 +01:00
}
if debug
{
2022-12-18 04:05:50 +01:00
println! ( " after: {:?} : {:?} , ' {} ' " , operation , queue , output ) ;
2022-12-14 09:34:41 +01:00
}
}
2023-12-22 22:13:17 +01:00
Ok ( output )
2022-12-14 09:34:41 +01:00
}
2022-12-21 21:48:52 +01:00
fn typecheck ( operations : & Vec < Operation > , functions : & Vec < Function > , intrinsics : & HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > , arrays : & Vec < Arr > , debug : bool ) -> Result < ( ) , String >
2022-12-14 04:12:03 +01:00
{
for function in functions
{
2022-12-14 07:57:51 +01:00
if debug
{
println! ( " Now typechecking function ' {} ' " , function . name ) ;
}
2022-12-21 21:48:52 +01:00
typecheck_block ( & function . content , & function . ins , & function . outs , functions , intrinsics , arrays , debug ) ? ;
2022-12-14 07:57:51 +01:00
if debug
{
println! ( " Successfully typechecked function ' {} ' " , function . name ) ;
}
2022-12-14 04:12:03 +01:00
}
2022-12-14 07:57:51 +01:00
if debug
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
println! ( " Now typechecking main operations " ) ;
}
2022-12-21 21:48:52 +01:00
typecheck_block ( operations , & Vec ::new ( ) , & Vec ::new ( ) , functions , intrinsics , arrays , debug ) ? ;
2022-12-14 07:57:51 +01:00
if debug
{
println! ( " Successfully typechecked main operations " ) ;
2022-12-14 04:12:03 +01:00
}
2023-12-22 22:13:17 +01:00
Ok ( ( ) )
2022-12-14 04:12:03 +01:00
}
2023-12-22 22:13:17 +01:00
fn typecheck_block ( operations : & Vec < Operation > , ins : & [ Datatype ] , outs : & Vec < Datatype > , functions : & Vec < Function > , intrinsics : & HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > , arrays : & Vec < Arr > , debug : bool ) -> Result < ( ) , String >
2022-12-14 04:12:03 +01:00
{
2022-12-21 21:48:52 +01:00
let actual_outs = get_return_type ( operations , ins , functions , intrinsics , arrays , debug ) ? ;
2022-12-14 07:57:51 +01:00
if & actual_outs ! = outs
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
let ( line , col ) = match operations . last ( )
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
Some ( operation ) = >
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
match operation
2022-12-14 04:12:03 +01:00
{
2023-01-03 20:39:08 +01:00
Operation ::Interrupt ( line , col ) |
2022-12-14 07:57:51 +01:00
Operation ::Enqueue ( _ , _ , line , col ) |
2022-12-15 20:34:56 +01:00
Operation ::Dequeue ( line , col ) |
2022-12-14 08:14:27 +01:00
Operation ::Requeue ( line , col ) |
2022-12-14 11:46:39 +01:00
Operation ::Dup ( line , col ) |
Operation ::Swap ( line , col ) |
2022-12-14 07:57:51 +01:00
Operation ::FunctionCall ( _ , line , col ) |
Operation ::If ( _ , _ , line , col ) |
Operation ::Intrinsic ( _ , line , col ) |
Operation ::While ( _ , line , col ) |
2022-12-15 20:34:56 +01:00
Operation ::QueueDiagnostic ( line , col ) |
2022-12-21 21:48:52 +01:00
Operation ::Apply ( _ , _ , line , col ) |
2022-12-15 20:34:56 +01:00
Operation ::Depth ( line , col ) = > ( * line , * col ) ,
2022-12-14 04:12:03 +01:00
}
}
2022-12-14 07:57:51 +01:00
None = > ( - 1 , - 1 )
} ;
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Wrong queue state at the end of a block, expected {:?} but got {:?} at {} : {} " , outs , actual_outs , line , col ) ) ;
2022-12-14 04:12:03 +01:00
}
2023-12-22 22:13:17 +01:00
Ok ( ( ) )
2022-12-14 04:12:03 +01:00
}
2023-12-22 22:13:17 +01:00
fn get_return_type ( operations : & Vec < Operation > , ins : & [ Datatype ] , functions : & Vec < Function > , intrinsics : & HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > , arrays : & Vec < Arr > , debug : bool ) -> Result < Vec < Datatype > , String >
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
let type_queue : & mut Vec < Datatype > = & mut Vec ::new ( ) ;
2022-12-14 04:12:03 +01:00
type_queue . extend_from_slice ( ins ) ;
2022-12-14 07:57:51 +01:00
let mut debug_string = String ::from ( " " ) ;
for operation in operations
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
if debug
{
debug_string = format! ( " operation: {:?} : {:?} " , operation , type_queue ) ;
}
match operation
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
Operation ::Dequeue ( line , col ) = >
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
if type_queue . is_empty ( )
2022-12-14 04:12:03 +01:00
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Attempted to dequeue an element while the queue was empty at {} : {} " , line , col ) ) ;
2022-12-14 07:57:51 +01:00
}
type_queue . remove ( 0 ) ;
}
Operation ::Enqueue ( datatype , _ , _ , _ ) = >
{
type_queue . push ( * datatype ) ;
}
2022-12-14 11:46:39 +01:00
Operation ::Dup ( line , col ) = >
{
if let Some ( typ ) = type_queue . get ( 0 )
{
2023-12-22 22:13:17 +01:00
type_queue . push ( * typ ) ;
2022-12-14 11:46:39 +01:00
}
else
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Attempted to dup an element while the queue was empty at {} : {} " , line , col ) ) ;
2022-12-14 11:46:39 +01:00
}
}
2022-12-14 08:14:27 +01:00
Operation ::Requeue ( line , col ) = >
{
if type_queue . is_empty ( )
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Attempted to requeue an element while the queue was empty at {} : {} " , line , col ) ) ;
2022-12-14 08:14:27 +01:00
}
let typ = type_queue . remove ( 0 ) ;
type_queue . push ( typ ) ;
}
2022-12-14 11:46:39 +01:00
Operation ::Swap ( line , col ) = >
{
if type_queue . is_empty ( )
{
2022-12-21 21:48:52 +01:00
return Err ( format! ( " Attempted to get the first element for a swap while the queue was empty at {} : {} " , line , col ) ) ;
2022-12-14 11:46:39 +01:00
}
let first_typ = type_queue . remove ( 0 ) ;
if type_queue . is_empty ( )
{
2022-12-21 21:48:52 +01:00
return Err ( format! ( " Attempted to get the second element for a swap while the queue was empty at {} : {} " , line , col ) ) ;
2022-12-14 11:46:39 +01:00
}
let second_typ = type_queue . remove ( 0 ) ;
type_queue . push ( second_typ ) ;
type_queue . push ( first_typ ) ;
}
2022-12-14 07:57:51 +01:00
Operation ::FunctionCall ( function_name , line , col ) = >
{
let function = functions . iter ( ) . find ( | x | & x . name = = function_name ) . unwrap ( ) ;
if function . ins . len ( ) > type_queue . len ( )
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Attempted to call function ' {} ' at {} : {} , with insufficient elements in the queue, expected {:?} but got {:?} " , function . name , line , col , function . ins , type_queue ) ) ;
2022-12-14 04:12:03 +01:00
}
2022-12-14 07:57:51 +01:00
for in_type in & function . ins
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
let actual_type = type_queue . remove ( 0 ) ;
if in_type ! = & actual_type
2022-12-14 04:12:03 +01:00
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Attempted to call function ' {} ' at {} : {} with a wrong parameter, expected {:?} but got {:?} " , function . name , line , col , in_type , actual_type ) ) ;
2022-12-14 04:12:03 +01:00
}
2022-12-14 07:57:51 +01:00
}
type_queue . extend_from_slice ( & function . outs ) ;
}
Operation ::If ( if_block , maybe_else_block , line , col ) = >
{
if type_queue . is_empty ( )
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Encountered if block with an empty queue at {} : {} " , line , col ) ) ;
2022-12-14 07:57:51 +01:00
}
let comparison_type = type_queue . remove ( 0 ) ;
2022-12-14 20:39:51 +01:00
if comparison_type ! = Datatype ::Bool
2022-12-14 07:57:51 +01:00
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Expected a Bool as an if condition but got {:?} instead at {} : {} " , comparison_type , line , col ) ) ;
2022-12-14 07:57:51 +01:00
}
if debug
{
println! ( " Starting to typecheck if block " ) ;
}
2023-12-22 22:13:17 +01:00
let if_ret = get_return_type ( if_block , type_queue , functions , intrinsics , arrays , debug ) ? ;
2022-12-14 07:57:51 +01:00
let else_ret =
if let Some ( else_block ) = maybe_else_block
{
if debug
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
println! ( " Starting to typecheck else block " ) ;
2022-12-14 04:12:03 +01:00
}
2023-12-22 22:13:17 +01:00
get_return_type ( else_block , type_queue , functions , intrinsics , arrays , debug ) ?
2022-12-14 04:12:03 +01:00
}
2022-12-14 07:57:51 +01:00
else
{
type_queue . clone ( )
} ;
if if_ret ! = else_ret
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Incompatible queue states after if/else construction, expected {:?} but got {:?} " , if_ret , else_ret ) ) ;
2022-12-14 07:57:51 +01:00
}
type_queue . clear ( ) ;
type_queue . extend_from_slice ( & if_ret ) ;
}
Operation ::Intrinsic ( intrinsic_name , line , col ) = >
{
let io = intrinsics . get ( intrinsic_name . as_str ( ) ) . unwrap ( ) ;
if io . 0. len ( ) > type_queue . len ( )
2022-12-14 04:12:03 +01:00
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Attempted to call intrinsic ' {} ' at {} : {} , with insufficient elements in the queue, expected {:?} but got {:?} " , intrinsic_name , line , col , io . 0 , type_queue ) ) ;
2022-12-14 07:57:51 +01:00
}
for in_type in & io . 0
{
let actual_type = type_queue . remove ( 0 ) ;
if in_type ! = & actual_type
2022-12-14 04:12:03 +01:00
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Attempted to call intrinsic ' {} ' at {} : {} with a wrong parameter, expected {:?} but got {:?} " , intrinsic_name , line , col , in_type , actual_type ) ) ;
2022-12-14 04:12:03 +01:00
}
}
2022-12-14 07:57:51 +01:00
type_queue . extend_from_slice ( & io . 1 ) ;
}
Operation ::While ( while_block , line , col ) = >
{
if type_queue . is_empty ( )
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Encountered while block with an empty queue at {} : {} " , line , col ) ) ;
2022-12-14 07:57:51 +01:00
}
2022-12-14 11:46:39 +01:00
let comparison_type = type_queue . remove ( 0 ) ;
2022-12-14 20:39:51 +01:00
if comparison_type ! = Datatype ::Bool
2022-12-14 07:57:51 +01:00
{
2022-12-21 21:48:52 +01:00
return Err ( format! ( " Expected a Bool as a while condition but got {:?} instead at {} : {} " , comparison_type , line , col ) ) ;
2022-12-14 07:57:51 +01:00
}
if debug
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
println! ( " Starting to typecheck while block " ) ;
2022-12-14 04:12:03 +01:00
}
2022-12-14 11:46:39 +01:00
let mut outs = type_queue . clone ( ) ;
2022-12-14 20:39:51 +01:00
outs . insert ( 0 , Datatype ::Bool ) ;
2022-12-21 21:48:52 +01:00
typecheck_block ( while_block , type_queue , & outs , functions , intrinsics , arrays , debug ) ? ;
2022-12-14 04:12:03 +01:00
}
2022-12-15 20:34:56 +01:00
Operation ::Depth ( _ , _ ) = >
{
type_queue . push ( Datatype ::Int ) ;
}
Operation ::QueueDiagnostic ( line , col ) = >
{
println! ( " ---Type queue state at {} : {} --- \n length: {} \n {:?} \n ------------------------------ " , line , col , type_queue . len ( ) , type_queue ) ;
}
2023-01-03 20:39:08 +01:00
Operation ::Interrupt ( _ , _ ) = > { }
2022-12-21 21:48:52 +01:00
Operation ::Apply ( name , word , line , col ) = >
{
match word . as_str ( )
{
" write " = >
{
if type_queue . is_empty ( ) | | type_queue . remove ( 0 ) ! = Datatype ::Int
{
return Err ( format! ( " Expected a position for a write application at {} : {} " , line , col ) ) ;
}
let expected_type = arrays . iter ( ) . find ( | x | & x . name = = name ) . unwrap ( ) . datatype ;
2022-12-22 00:47:41 +01:00
if type_queue . is_empty ( )
{
return Err ( format! ( " Expected data for a write application at {} : {} " , line , col ) ) ;
}
2022-12-21 21:48:52 +01:00
let actual_type = type_queue . remove ( 0 ) ;
if actual_type ! = expected_type
{
return Err ( format! ( " Expected a {:?} value but got a {:?} value at {} : {} " , expected_type , actual_type , line , col ) ) ;
}
}
" read " = >
{
if type_queue . is_empty ( ) | | type_queue . remove ( 0 ) ! = Datatype ::Int
{
return Err ( format! ( " Expected a position for a read application at {} : {} " , line , col ) ) ;
}
let typ = arrays . iter ( ) . find ( | x | & x . name = = name ) . unwrap ( ) . datatype ;
type_queue . push ( typ ) ;
}
" length " = >
{
type_queue . push ( Datatype ::Int ) ;
}
_ = > return Err ( format! ( " Encountered unknown application ' {} ' at {} : {} " , word , line , col ) )
}
}
2022-12-14 04:12:03 +01:00
}
2022-12-14 07:57:51 +01:00
if debug
{
println! ( " {} => {:?} " , debug_string , type_queue ) ;
}
2022-12-14 04:12:03 +01:00
}
2023-12-22 22:13:17 +01:00
Ok ( type_queue . clone ( ) )
2022-12-14 04:12:03 +01:00
}
2023-12-22 22:13:17 +01:00
fn validate_function_calls ( operations : & Vec < Operation > , functions : & Vec < Function > , debug : bool ) -> Result < ( ) , String >
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
for function in functions
2022-12-05 00:38:20 +01:00
{
2023-12-22 22:13:17 +01:00
validate_function_calls_in_block ( & function . content , functions ) ? ;
2022-12-14 07:57:51 +01:00
if debug
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
println! ( " Successfully validated function calls in function ' {} ' " , function . name ) ;
}
}
2023-12-22 22:13:17 +01:00
validate_function_calls_in_block ( operations , functions ) ? ;
2022-12-14 07:57:51 +01:00
if debug
{
println! ( " Successfully validated function calls in main operations " ) ;
}
2023-12-22 22:13:17 +01:00
Ok ( ( ) )
2022-12-14 07:57:51 +01:00
}
2023-12-22 22:13:17 +01:00
fn validate_function_calls_in_block ( block : & Vec < Operation > , functions : & Vec < Function > ) -> Result < ( ) , String >
2022-12-14 07:57:51 +01:00
{
for operation in block
{
match operation
{
2022-12-15 20:34:56 +01:00
Operation ::Depth ( _ , _ ) | Operation ::QueueDiagnostic ( _ , _ ) | Operation ::Intrinsic ( _ , _ , _ ) | Operation ::Enqueue ( _ , _ , _ , _ ) | Operation ::Dequeue ( _ , _ ) |
2023-01-03 20:39:08 +01:00
Operation ::Requeue ( _ , _ ) | Operation ::Dup ( _ , _ ) | Operation ::Swap ( _ , _ ) | Operation ::Apply ( _ , _ , _ , _ ) | Operation ::Interrupt ( _ , _ ) = > { } ,
2022-12-14 07:57:51 +01:00
Operation ::FunctionCall ( function_name , line , col ) = >
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
if ! functions . iter ( ) . any ( | x | & x . name = = function_name )
2022-12-05 00:38:20 +01:00
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Call to unknown function ' {} ' at {} : {} " , function_name , line , col ) ) ;
2022-12-05 00:38:20 +01:00
}
}
2022-12-14 07:57:51 +01:00
Operation ::If ( if_block , maybe_else_block , _ , _ ) = >
2022-12-05 00:38:20 +01:00
{
2023-12-22 22:13:17 +01:00
validate_function_calls_in_block ( if_block , functions ) ? ;
2022-12-14 07:57:51 +01:00
if let Some ( else_block ) = maybe_else_block
2022-12-05 00:38:20 +01:00
{
2023-12-22 22:13:17 +01:00
validate_function_calls_in_block ( else_block , functions ) ? ;
2022-12-05 00:38:20 +01:00
}
}
2022-12-14 07:57:51 +01:00
Operation ::While ( while_block , _ , _ ) = >
2022-12-05 00:38:20 +01:00
{
2023-12-22 22:13:17 +01:00
validate_function_calls_in_block ( while_block , functions ) ? ;
2022-12-14 07:57:51 +01:00
}
}
}
2023-12-22 22:13:17 +01:00
Ok ( ( ) )
2022-12-14 07:57:51 +01:00
}
2023-12-22 22:13:17 +01:00
fn extract_arrays ( tokens : & mut Vec < Token > , intrinsics : & HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > , functions : & [ Function ] , debug : bool ) -> Result < Vec < Arr > , String >
2022-12-21 21:48:52 +01:00
{
let mut tokens_iter = tokens . iter ( ) . peekable ( ) ;
let mut arrays : Vec < Arr > = Vec ::new ( ) ;
let mut new_tokens : Vec < Token > = Vec ::new ( ) ;
while let Some ( token ) = tokens_iter . next ( )
{
if let Token ::Keyword ( word , line , col ) = token
{
if word = = " arr "
{
if debug
{
println! ( " Found an array at {} : {} " , line , col ) ;
}
if let Some ( Token ::Keyword ( name , _ , _ ) ) = tokens_iter . next ( )
{
if functions . iter ( ) . any ( | x | & x . name = = name )
{
return Err ( format! ( " Cannot redeclare an array with the same name as a function {} : {} " , line , col ) ) ;
}
if arrays . iter ( ) . any ( | x | & x . name = = name )
{
return Err ( format! ( " Cannot redeclare an array with the same name as an array {} : {} " , line , col ) ) ;
}
if intrinsics . contains_key ( name . as_str ( ) )
{
return Err ( format! ( " An array cannot have the same name as an intrinsic ( {} ) at {} : {} " , name , line , col ) ) ;
}
if let Some ( Token ::Keyword ( open_curly , _ , _ ) ) = tokens_iter . next ( )
{
if open_curly ! = " { "
{
return Err ( format! ( " Expected ' {{ ' in array declaration at {} : {} " , line , col ) ) ;
}
}
else
{
return Err ( format! ( " Reached the end of the file while parsing an array at {} : {} " , line , col ) ) ;
}
if let Some ( Token ::Keyword ( typ , _ , _ ) ) = tokens_iter . next ( )
{
let datatype = str_to_datatype ( typ , * line , * col ) ? ;
if let Some ( Token ::IntLit ( size_str , _ , _ ) ) = tokens_iter . next ( )
{
let size = size_str . parse ::< i64 > ( ) . unwrap ( ) ;
if let Some ( Token ::Keyword ( close_curly , _ , _ ) ) = tokens_iter . next ( )
{
if close_curly ! = " } "
{
return Err ( format! ( " Expected ' }} ' in array declaration at {} : {} " , line , col ) ) ;
}
}
else
{
return Err ( format! ( " Reached the end of the file while parsing an array at {} : {} " , line , col ) ) ;
}
let mut data : Vec < String > = Vec ::new ( ) ;
let default_val = match datatype
{
2022-12-31 16:09:55 +01:00
Datatype ::String = > String ::new ( ) ,
2022-12-21 21:48:52 +01:00
Datatype ::Bool = > String ::from ( " false " ) ,
Datatype ::Int = > String ::from ( " 0 " ) ,
} ;
for _ in 0 .. size
{
data . push ( default_val . clone ( ) ) ;
}
2023-01-03 21:52:48 +01:00
arrays . push ( Arr { name : sanitize_name ( name . clone ( ) ) , datatype , length : size , data } ) ;
2022-12-21 21:48:52 +01:00
}
}
else
{
return Err ( format! ( " Reached the end of the file while parsing an array at {} : {} " , line , col ) )
}
}
else
{
return Err ( format! ( " Expected array name, at {} : {} " , line , col ) ) ;
}
}
else
{
new_tokens . push ( token . clone ( ) ) ;
}
}
else
{
new_tokens . push ( token . clone ( ) ) ;
}
}
tokens . clear ( ) ;
tokens . extend_from_slice ( & new_tokens ) ;
2023-12-22 22:13:17 +01:00
Ok ( arrays )
2022-12-21 21:48:52 +01:00
}
2023-01-03 21:52:48 +01:00
fn sanitize_name ( name : String ) -> String
{
2023-12-22 22:13:17 +01:00
if name = = " test "
{
return " test_ " . to_string ( ) ;
}
name . replace ( [ '-' , '+' ] , " _ " ) . replace ( '%' , " percent " ) . replace ( '/' , " slash " )
2023-01-03 21:52:48 +01:00
}
2022-12-21 21:48:52 +01:00
fn str_to_datatype ( s : & str , line : i32 , col : i32 ) -> Result < Datatype , String >
{
match s
{
2022-12-31 16:09:55 +01:00
//"any" => Ok(Datatype::Any),
2022-12-21 21:48:52 +01:00
" bool " = > Ok ( Datatype ::Bool ) ,
" int " = > Ok ( Datatype ::Int ) ,
" str " = > Ok ( Datatype ::String ) ,
2023-12-22 22:13:17 +01:00
_ = > Err ( format! ( " Expected a datatype for the array, got {} instead at {} : {} " , s , line , col ) )
2022-12-21 21:48:52 +01:00
}
}
2023-02-06 15:00:37 +01:00
fn extract_functions ( tokens : & mut Vec < Token > , functions : & mut Vec < Function > , intrinsics : & HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > , debug : bool ) -> Result < ( ) , String >
2022-12-14 07:57:51 +01:00
{
let mut tokens_iter = tokens . iter ( ) . peekable ( ) ;
let mut new_tokens : Vec < Token > = Vec ::new ( ) ;
while let Some ( token ) = tokens_iter . next ( )
{
if let Token ::Keyword ( word , line , col ) = token
{
if word = = " function "
{
if debug
2022-12-05 00:38:20 +01:00
{
2022-12-15 20:34:56 +01:00
println! ( " Found a function at {} : {} " , line , col ) ;
2022-12-14 07:57:51 +01:00
}
let mut ins : Vec < Datatype > = Vec ::new ( ) ;
loop
{
let maybe_token = tokens_iter . next ( ) ;
match maybe_token
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
Some ( token ) = >
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
match token
2022-12-05 00:38:20 +01:00
{
2023-01-23 03:58:53 +01:00
Token ::IntLit ( _ , line , col ) | Token ::StringLit ( _ , line , col ) | Token ::BoolLit ( _ , line , col ) | Token ::Import ( line , col ) |
2022-12-21 21:48:52 +01:00
Token ::Apply ( _ , _ , line , col ) = >
2022-12-14 07:57:51 +01:00
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Expected input parameters for a function but got {:?} instead at {} : {} " , token , line , col ) ) ;
2022-12-14 07:57:51 +01:00
}
Token ::Keyword ( word , line , col ) = >
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
if word = = " => "
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
break ;
2022-12-05 00:38:20 +01:00
}
2022-12-14 07:57:51 +01:00
match word . as_str ( )
2022-12-14 04:12:03 +01:00
{
2022-12-31 16:09:55 +01:00
//"any" => ins.push(Datatype::Any),
2022-12-14 07:57:51 +01:00
" str " = > ins . push ( Datatype ::String ) ,
" int " = > ins . push ( Datatype ::Int ) ,
2022-12-14 20:39:51 +01:00
" bool " = > ins . push ( Datatype ::Bool ) ,
2022-12-15 21:53:01 +01:00
_ = > return Err ( format! ( " Expected input parameters for a function but got {} instead at {} : {} " , word , line , col ) )
2022-12-14 04:12:03 +01:00
}
2022-12-05 00:38:20 +01:00
}
}
}
2023-12-22 22:13:17 +01:00
None = > return Err ( " Unexpected end of file while extracting a function " . to_string ( ) )
2022-12-05 00:38:20 +01:00
}
}
2022-12-14 07:57:51 +01:00
if debug
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
println! ( " ins: {:?} " , ins ) ;
2022-12-05 00:38:20 +01:00
}
2022-12-14 07:57:51 +01:00
let mut outs : Vec < Datatype > = Vec ::new ( ) ;
loop
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
let maybe_token = tokens_iter . next ( ) ;
match maybe_token
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
Some ( token ) = >
2022-12-14 04:12:03 +01:00
{
2022-12-14 07:57:51 +01:00
match token
2022-12-14 04:12:03 +01:00
{
2023-01-23 03:58:53 +01:00
Token ::IntLit ( _ , line , col ) | Token ::StringLit ( _ , line , col ) | Token ::BoolLit ( _ , line , col ) | Token ::Import ( line , col ) |
2022-12-21 21:48:52 +01:00
Token ::Apply ( _ , _ , line , col ) = >
2022-12-14 07:57:51 +01:00
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Expected input parameters for a function but got {:?} instead at {} : {} " , token , line , col ) ) ;
2022-12-14 07:57:51 +01:00
}
Token ::Keyword ( word , line , col ) = >
{
match word . as_str ( )
{
2022-12-31 16:09:55 +01:00
//"any" => outs.push(Datatype::Any),
2022-12-14 07:57:51 +01:00
" str " = > outs . push ( Datatype ::String ) ,
" int " = > outs . push ( Datatype ::Int ) ,
2022-12-15 20:34:56 +01:00
" bool " = > outs . push ( Datatype ::Bool ) ,
2023-02-06 15:00:37 +01:00
" { " | " } " | " deq " | " req " | " dup " | " swp " | " true " | " false " | " depth " | " ??? " | " import " = > return Err ( format! ( " Expected function name but got {} at {} : {} " , word , line , col ) ) ,
2022-12-14 07:57:51 +01:00
_ = >
{
if functions . iter ( ) . any ( | x | & x . name = = word )
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Redeclaration of function ' {} ' at {} : {} " , word , line , col ) ) ;
2022-12-14 07:57:51 +01:00
}
2022-12-14 09:34:41 +01:00
if intrinsics . contains_key ( word . as_str ( ) )
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Function name {} at {} : {} is already an intrinsic " , word , line , col ) ) ;
2022-12-14 09:34:41 +01:00
}
2022-12-14 07:57:51 +01:00
if debug
{
println! ( " outs: {:?} " , outs ) ;
2023-01-03 17:07:57 +01:00
}
2022-12-15 21:53:01 +01:00
let block = parse_block ( & mut tokens_iter , intrinsics , debug ) ? ;
2023-01-03 21:52:48 +01:00
functions . push ( Function { name : sanitize_name ( word . clone ( ) ) , ins , outs , content : block } ) ;
2022-12-14 07:57:51 +01:00
break ;
}
}
}
2022-12-14 04:12:03 +01:00
}
}
2023-12-22 22:13:17 +01:00
None = > return Err ( " Unexpected end of file while extracting a function " . to_string ( ) )
2022-12-05 00:38:20 +01:00
}
}
}
2022-12-14 07:57:51 +01:00
else
{
new_tokens . push ( token . clone ( ) ) ;
}
}
else
{
new_tokens . push ( token . clone ( ) ) ;
2022-12-05 00:38:20 +01:00
}
2022-12-14 07:57:51 +01:00
}
tokens . clear ( ) ;
tokens . extend_from_slice ( & new_tokens ) ;
2023-12-22 22:13:17 +01:00
Ok ( ( ) )
2022-12-14 07:57:51 +01:00
}
2022-12-05 00:38:20 +01:00
2022-12-15 21:53:01 +01:00
fn parse_block ( tokens_iter : & mut Peekable < std ::slice ::Iter < Token > > , intrinsics : & HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > , debug : bool ) -> Result < Vec < Operation > , String >
2022-12-14 07:57:51 +01:00
{
if let Some ( Token ::Keyword ( word , line , col ) ) = tokens_iter . next ( )
{
if word ! = " { "
2022-12-05 00:38:20 +01:00
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Expected ' {{ ' to open a block but got {} at {} : {} " , word , line , col ) ) ;
2022-12-05 00:38:20 +01:00
}
}
2022-12-14 07:57:51 +01:00
else
2022-12-05 00:38:20 +01:00
{
2023-12-22 22:13:17 +01:00
return Err ( " Expected '{' to open a block " . to_string ( ) ) ;
2022-12-05 00:38:20 +01:00
}
2023-12-22 22:13:17 +01:00
parse_until_delimiter ( tokens_iter , intrinsics , Some ( " } " ) , debug )
2022-12-05 00:38:20 +01:00
}
2022-12-15 21:53:01 +01:00
fn parse_until_delimiter ( tokens_iter : & mut Peekable < std ::slice ::Iter < Token > > , intrinsics : & HashMap < & str , ( Vec < Datatype > , Vec < Datatype > ) > , delimiter : Option < & str > , debug : bool ) -> Result < Vec < Operation > , String >
2022-12-05 00:38:20 +01:00
{
2022-12-14 07:57:51 +01:00
let mut operations : Vec < Operation > = Vec ::new ( ) ;
loop
{
let maybe_token = tokens_iter . next ( ) ;
match maybe_token
{
Some ( token ) = >
{
match token
{
Token ::IntLit ( value , line , col ) = >
{
operations . push ( Operation ::Enqueue ( Datatype ::Int , value . clone ( ) , * line , * col ) ) ;
}
Token ::StringLit ( value , line , col ) = >
{
operations . push ( Operation ::Enqueue ( Datatype ::String , value . clone ( ) , * line , * col ) ) ;
}
2022-12-14 20:39:51 +01:00
Token ::BoolLit ( value , line , col ) = >
{
operations . push ( Operation ::Enqueue ( Datatype ::Bool , value . clone ( ) , * line , * col ) ) ;
}
2022-12-21 21:48:52 +01:00
Token ::Apply ( name , word , line , col ) = >
{
2023-01-03 21:52:48 +01:00
operations . push ( Operation ::Apply ( sanitize_name ( name . clone ( ) ) , word . clone ( ) , * line , * col ) ) ;
2022-12-21 21:48:52 +01:00
}
2023-01-23 03:58:53 +01:00
Token ::Import ( line , col ) = >
{
2023-01-23 05:28:13 +01:00
return Err ( format! ( " Unexpected import token at {} : {} , should have been resolved before, probably a compiler bug " , line , col ) ) ;
2023-01-23 03:58:53 +01:00
}
2022-12-14 07:57:51 +01:00
Token ::Keyword ( word , line , col ) = >
{
if intrinsics . contains_key ( word . as_str ( ) )
{
operations . push ( Operation ::Intrinsic ( word . clone ( ) , * line , * col ) ) ;
}
else if word = = " if "
{
2022-12-15 21:53:01 +01:00
let block = parse_block ( tokens_iter , intrinsics , debug ) ? ;
2022-12-14 07:57:51 +01:00
let else_block =
if let Some ( Token ::Keyword ( maybe_else , _ , _ ) ) = tokens_iter . peek ( )
{
if maybe_else = = " else "
{
tokens_iter . next ( ) ;
2022-12-15 21:53:01 +01:00
Some ( parse_block ( tokens_iter , intrinsics , debug ) ? )
2022-12-14 07:57:51 +01:00
}
else
{
None
}
}
else
{
None
} ;
operations . push ( Operation ::If ( block , else_block , * line , * col ) ) ;
}
else if word = = " while "
{
2022-12-15 21:53:01 +01:00
operations . push ( Operation ::While ( parse_block ( tokens_iter , intrinsics , debug ) ? , * line , * col ) ) ;
2022-12-14 07:57:51 +01:00
}
else if word = = " deq "
{
operations . push ( Operation ::Dequeue ( * line , * col ) ) ;
}
2022-12-14 08:14:27 +01:00
else if word = = " req "
{
operations . push ( Operation ::Requeue ( * line , * col ) ) ;
}
2022-12-14 11:46:39 +01:00
else if word = = " dup "
{
operations . push ( Operation ::Dup ( * line , * col ) ) ;
}
else if word = = " swp "
{
operations . push ( Operation ::Swap ( * line , * col ) ) ;
}
2022-12-15 20:34:56 +01:00
else if word = = " depth "
{
operations . push ( Operation ::Depth ( * line , * col ) ) ;
}
else if word = = " ??? "
{
operations . push ( Operation ::QueueDiagnostic ( * line , * col ) ) ;
}
2023-01-03 20:39:08 +01:00
else if word = = " interrupt "
{
operations . push ( Operation ::Interrupt ( * line , * col ) ) ;
}
2022-12-14 07:57:51 +01:00
else if Some ( word . as_str ( ) ) = = delimiter
{
2022-12-15 21:53:01 +01:00
return Ok ( operations ) ;
2022-12-14 07:57:51 +01:00
}
else if word = = " { " | | word = = " function "
{
2022-12-15 21:53:01 +01:00
return Err ( format! ( " Unexpected keyword {} at {} : {} " , word , line , col ) ) ;
2022-12-14 07:57:51 +01:00
}
else
{
2023-01-03 21:52:48 +01:00
operations . push ( Operation ::FunctionCall ( sanitize_name ( word . clone ( ) ) , * line , * col ) ) ;
2022-12-14 07:57:51 +01:00
}
}
}
}
None = >
{
if delimiter . is_some ( )
{
2023-12-22 22:13:17 +01:00
return Err ( " Reached the end of the file while parsing a block " . to_string ( ) ) ;
2022-12-14 07:57:51 +01:00
}
else
{
2022-12-15 21:53:01 +01:00
return Ok ( operations ) ;
2022-12-14 07:57:51 +01:00
}
}
}
}
2022-12-05 00:38:20 +01:00
}
fn usage ( )
{
println! ( " Usage: kurz -c path/to/file " ) ;
exit ( 0 ) ;
}
2022-12-15 21:53:01 +01:00
fn tokenize ( text : & str ) -> Result < Vec < Token > , String >
2022-11-29 02:04:01 +01:00
{
let mut tokens : Vec < Token > = Vec ::new ( ) ;
let mut line = 1 ;
let mut col = 1 ;
let mut state = TokenizerState ::Whitespace ;
let mut word = String ::new ( ) ;
2022-12-05 00:38:20 +01:00
let mut iter = text . chars ( ) . peekable ( ) ;
2022-12-21 21:48:52 +01:00
let mut application_name = String ::new ( ) ;
2022-12-05 00:38:20 +01:00
while let Some ( ch ) = iter . next ( )
2022-11-29 02:04:01 +01:00
{
2022-12-05 00:38:20 +01:00
if ch = = '/' & & iter . peek ( ) = = Some ( & '/' )
{
state = TokenizerState ::Comment ;
}
2022-11-29 02:04:01 +01:00
match state
{
2022-12-05 00:38:20 +01:00
TokenizerState ::Comment = >
{
if ch = = '\n'
{
state = TokenizerState ::Whitespace ;
}
}
2022-11-29 02:04:01 +01:00
TokenizerState ::Whitespace = >
{
// If ch is whitespace, do nothing
if ! ch . is_whitespace ( )
{
match ch
{
'"' = >
{
state = TokenizerState ::Quote ;
}
_ = >
{
2022-12-05 00:38:20 +01:00
state = TokenizerState ::Keyword ;
2022-11-29 02:04:01 +01:00
word . push ( ch ) ;
}
}
}
}
TokenizerState ::Quote = >
{
if ch = = '"'
{
state = TokenizerState ::Whitespace ;
2022-12-14 20:39:51 +01:00
tokens . push ( Token ::StringLit ( word . clone ( ) . replace ( " \\ n " , " \n " ) , line , col ) ) ;
2022-11-29 02:04:01 +01:00
word . clear ( ) ;
}
else
{
word . push ( ch ) ;
}
}
2022-12-05 00:38:20 +01:00
TokenizerState ::Keyword = >
2022-11-29 02:04:01 +01:00
{
if ch . is_whitespace ( )
{
state = TokenizerState ::Whitespace ;
2022-12-21 21:48:52 +01:00
if application_name . is_empty ( )
2022-12-05 00:38:20 +01:00
{
2023-12-22 22:13:17 +01:00
if word . parse ::< i64 > ( ) . is_ok ( )
2022-12-21 21:48:52 +01:00
{
tokens . push ( Token ::IntLit ( word . clone ( ) , line , col ) ) ;
}
else if word = = " true " | | word = = " false "
{
tokens . push ( Token ::BoolLit ( word . clone ( ) , line , col ) ) ;
}
2023-01-23 05:28:13 +01:00
else if word = = " import "
{
tokens . push ( Token ::Import ( line , col ) ) ;
}
2022-12-21 21:48:52 +01:00
else
{
tokens . push ( Token ::Keyword ( word . clone ( ) , line , col ) ) ;
}
2022-12-14 20:39:51 +01:00
}
2022-12-05 00:38:20 +01:00
else
2022-11-29 02:04:01 +01:00
{
2023-01-03 21:52:48 +01:00
tokens . push ( Token ::Apply ( sanitize_name ( application_name . clone ( ) ) , word . clone ( ) , line , col ) ) ;
2022-12-21 21:48:52 +01:00
application_name . clear ( ) ;
2022-12-05 00:38:20 +01:00
}
word . clear ( ) ;
2022-11-29 02:04:01 +01:00
}
else
{
match ch
{
2023-12-22 22:13:17 +01:00
'"' = > return Err ( " Having ' \" ' in the middle of a word is not allowed " . to_string ( ) ) ,
2022-12-21 21:48:52 +01:00
'.' = >
{
application_name = word . clone ( ) ;
word . clear ( ) ;
}
2022-11-29 02:04:01 +01:00
_ = >
{
word . push ( ch ) ;
}
}
}
}
}
col + = 1 ;
if ch = = '\n'
{
col = 1 ;
line + = 1 ;
}
}
match state
{
TokenizerState ::Quote = >
{
2023-12-22 22:13:17 +01:00
return Err ( " Encountered EOF before closing string " . to_string ( ) ) ;
2022-11-29 02:04:01 +01:00
}
2022-12-05 00:38:20 +01:00
TokenizerState ::Whitespace | TokenizerState ::Comment = > { } ,
TokenizerState ::Keyword = >
2022-11-29 02:04:01 +01:00
{
2022-12-22 00:47:41 +01:00
if application_name . is_empty ( )
{
tokens . push ( Token ::Keyword ( word . clone ( ) , line , col ) ) ;
}
else
{
2023-01-03 21:52:48 +01:00
tokens . push ( Token ::Apply ( sanitize_name ( application_name . clone ( ) ) , word . clone ( ) , line , col ) ) ;
2022-12-22 00:47:41 +01:00
}
2022-11-29 02:04:01 +01:00
}
}
2022-12-15 21:53:01 +01:00
Ok ( tokens )
2022-11-29 02:04:01 +01:00
}