Add formatting disassembly output into JSON or TOML
This commit is contained in:
parent
e387579a81
commit
71a92c078b
85
Cargo.lock
generated
85
Cargo.lock
generated
@ -96,6 +96,15 @@ version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "basic-toml"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@ -328,11 +337,13 @@ dependencies = [
|
||||
name = "dust-cli"
|
||||
version = "0.5.0"
|
||||
dependencies = [
|
||||
"basic-toml",
|
||||
"clap 4.5.20",
|
||||
"color-print",
|
||||
"dust-lang",
|
||||
"postcard",
|
||||
"serde_json",
|
||||
"toml",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
]
|
||||
@ -360,6 +371,12 @@ version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.10"
|
||||
@ -398,6 +415,12 @@ dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
|
||||
|
||||
[[package]]
|
||||
name = "heapless"
|
||||
version = "0.7.17"
|
||||
@ -427,6 +450,16 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.1"
|
||||
@ -792,6 +825,15 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.7"
|
||||
@ -899,6 +941,40 @@ dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02a8b472d1a3d7c18e2d61a489aee3453fd9031c33e4f55bd533f4a7adca1bee"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.41"
|
||||
@ -1237,6 +1313,15 @@ version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86e376c75f4f43f44db463cf729e0d3acbf954d13e22c51e26e4c264b4ab545f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
|
@ -13,6 +13,7 @@ name = "dust"
|
||||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
basic-toml = "0.1.9"
|
||||
clap = { version = "4.5.14", features = [
|
||||
"cargo",
|
||||
"color",
|
||||
@ -24,5 +25,6 @@ color-print = "0.3.7"
|
||||
dust-lang = { path = "../dust-lang" }
|
||||
postcard = "1.0.10"
|
||||
serde_json = "1.0.133"
|
||||
toml = "0.8.20"
|
||||
tracing = "0.1.41"
|
||||
tracing-subscriber = "0.3.19"
|
||||
|
@ -1,19 +1,19 @@
|
||||
use std::{
|
||||
fs::read_to_string,
|
||||
io::{self, stdout, Read},
|
||||
io::{self, Read, stdout},
|
||||
path::PathBuf,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use clap::{
|
||||
builder::{styling::AnsiColor, Styles},
|
||||
Args, ColorChoice, Error, Parser, Subcommand, ValueEnum, ValueHint,
|
||||
builder::{Styles, styling::AnsiColor},
|
||||
crate_authors, crate_description, crate_version,
|
||||
error::ErrorKind,
|
||||
Args, ColorChoice, Error, Parser, Subcommand, ValueHint,
|
||||
};
|
||||
use color_print::{cformat, cstr};
|
||||
use dust_lang::{CompileError, Compiler, DustError, DustString, Lexer, Span, Token, Vm};
|
||||
use tracing::{subscriber::set_global_default, Level};
|
||||
use tracing::{Level, subscriber::set_global_default};
|
||||
use tracing_subscriber::FmtSubscriber;
|
||||
|
||||
const ABOUT: &str = cstr!(
|
||||
@ -158,11 +158,14 @@ enum Mode {
|
||||
style: bool,
|
||||
|
||||
/// Custom program name, overrides the file name
|
||||
#[arg(long)]
|
||||
#[arg(short, long)]
|
||||
name: Option<DustString>,
|
||||
|
||||
#[command(flatten)]
|
||||
input: Input,
|
||||
|
||||
#[arg(short, long, default_value = "cli")]
|
||||
format: Format,
|
||||
},
|
||||
|
||||
/// Lex the source code and print the tokens
|
||||
@ -180,6 +183,13 @@ enum Mode {
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Clone, Copy)]
|
||||
enum Format {
|
||||
Cli,
|
||||
Json,
|
||||
Toml,
|
||||
}
|
||||
|
||||
fn get_source_and_file_name(input: Input) -> (String, Option<DustString>) {
|
||||
if let Some(path) = input.file {
|
||||
let source = read_to_string(&path).expect("Failed to read source file");
|
||||
@ -221,88 +231,6 @@ fn main() {
|
||||
|
||||
set_global_default(subscriber).expect("Failed to set tracing subscriber");
|
||||
|
||||
if let Mode::Disassemble { style, name, input } = mode {
|
||||
let (source, file_name) = get_source_and_file_name(input);
|
||||
let lexer = Lexer::new(&source);
|
||||
let program_name = name.or(file_name);
|
||||
let mut compiler = match Compiler::new(lexer, program_name, true) {
|
||||
Ok(compiler) => compiler,
|
||||
Err(error) => {
|
||||
handle_compile_error(error, &source);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match compiler.compile() {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
handle_compile_error(error, &source);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let chunk = compiler.finish();
|
||||
let mut stdout = stdout().lock();
|
||||
|
||||
chunk
|
||||
.disassembler(&mut stdout)
|
||||
.width(65)
|
||||
.style(style)
|
||||
.source(&source)
|
||||
.disassemble()
|
||||
.expect("Failed to write disassembly to stdout");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if let Mode::Tokenize { input, .. } = mode {
|
||||
let (source, _) = get_source_and_file_name(input);
|
||||
let mut lexer = Lexer::new(&source);
|
||||
let mut next_token = || -> Option<(Token, Span, bool)> {
|
||||
match lexer.next_token() {
|
||||
Ok((token, position)) => Some((token, position, lexer.is_eof())),
|
||||
Err(error) => {
|
||||
let report = DustError::compile(CompileError::Lex(error), &source).report();
|
||||
|
||||
eprintln!("{report}");
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
println!("{:^66}", "Tokens");
|
||||
|
||||
for _ in 0..66 {
|
||||
print!("-");
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("{:^21}|{:^22}|{:^22}", "Kind", "Value", "Position");
|
||||
|
||||
for _ in 0..66 {
|
||||
print!("-");
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
while let Some((token, position, is_eof)) = next_token() {
|
||||
if is_eof {
|
||||
break;
|
||||
}
|
||||
|
||||
let token_kind = token.kind().to_string();
|
||||
let token = token.to_string();
|
||||
let position = position.to_string();
|
||||
|
||||
println!("{token_kind:^21}|{token:^22}|{position:^22}");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if let Mode::Run(Run {
|
||||
time,
|
||||
no_output,
|
||||
@ -352,6 +280,111 @@ fn main() {
|
||||
print_time("Run Time", run_time);
|
||||
print_time("Total Time", total_time);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if let Mode::Disassemble {
|
||||
style,
|
||||
name,
|
||||
input,
|
||||
format,
|
||||
} = mode
|
||||
{
|
||||
let (source, file_name) = get_source_and_file_name(input);
|
||||
let lexer = Lexer::new(&source);
|
||||
let program_name = name.or(file_name);
|
||||
let mut compiler = match Compiler::new(lexer, program_name, true) {
|
||||
Ok(compiler) => compiler,
|
||||
Err(error) => {
|
||||
handle_compile_error(error, &source);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
match compiler.compile() {
|
||||
Ok(()) => {}
|
||||
Err(error) => {
|
||||
handle_compile_error(error, &source);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let chunk = compiler.finish();
|
||||
let mut stdout = stdout().lock();
|
||||
|
||||
match format {
|
||||
Format::Cli => {
|
||||
chunk
|
||||
.disassembler(&mut stdout)
|
||||
.width(65)
|
||||
.style(style)
|
||||
.source(&source)
|
||||
.disassemble()
|
||||
.expect("Failed to write disassembly to stdout");
|
||||
}
|
||||
Format::Json => {
|
||||
let json = serde_json::to_string_pretty(&chunk)
|
||||
.expect("Failed to serialize chunk to JSON");
|
||||
|
||||
println!("{json}");
|
||||
}
|
||||
Format::Toml => {
|
||||
let toml = basic_toml::to_string(&chunk)
|
||||
.inspect_err(|error| println!("{:?}", error.to_string()))
|
||||
.expect("Failed to serialize chunk to TOML");
|
||||
|
||||
println!("{toml}");
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if let Mode::Tokenize { input, .. } = mode {
|
||||
let (source, _) = get_source_and_file_name(input);
|
||||
let mut lexer = Lexer::new(&source);
|
||||
let mut next_token = || -> Option<(Token, Span, bool)> {
|
||||
match lexer.next_token() {
|
||||
Ok((token, position)) => Some((token, position, lexer.is_eof())),
|
||||
Err(error) => {
|
||||
let report = DustError::compile(CompileError::Lex(error), &source).report();
|
||||
|
||||
eprintln!("{report}");
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
println!("{:^66}", "Tokens");
|
||||
|
||||
for _ in 0..66 {
|
||||
print!("-");
|
||||
}
|
||||
|
||||
println!();
|
||||
println!("{:^21}|{:^22}|{:^22}", "Kind", "Value", "Position");
|
||||
|
||||
for _ in 0..66 {
|
||||
print!("-");
|
||||
}
|
||||
|
||||
println!();
|
||||
|
||||
while let Some((token, position, is_eof)) = next_token() {
|
||||
if is_eof {
|
||||
break;
|
||||
}
|
||||
|
||||
let token_kind = token.kind().to_string();
|
||||
let token = token.to_string();
|
||||
let position = position.to_string();
|
||||
|
||||
println!("{token_kind:^21}|{token:^22}|{position:^22}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,12 +13,12 @@ pub struct Local {
|
||||
/// Index of the register where the variable's value is stored.
|
||||
pub register_index: u16,
|
||||
|
||||
/// Type of the variable's value.
|
||||
pub r#type: Type,
|
||||
|
||||
/// Whether the local is mutable.
|
||||
pub is_mutable: bool,
|
||||
|
||||
/// Type of the variable's value.
|
||||
pub r#type: Type,
|
||||
|
||||
/// Scope where the variable was declared.
|
||||
pub scope: Scope,
|
||||
}
|
||||
|
@ -20,19 +20,20 @@ mod scope;
|
||||
pub use disassembler::Disassembler;
|
||||
pub use local::Local;
|
||||
pub use scope::Scope;
|
||||
use serde::ser::SerializeStruct;
|
||||
|
||||
use std::fmt::{self, Debug, Display, Formatter, Write as FmtWrite};
|
||||
use std::io::Write;
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
|
||||
use crate::{ConcreteValue, DustString, Function, FunctionType, Instruction, Span};
|
||||
|
||||
/// Representation of a Dust program or function.
|
||||
///
|
||||
/// See the [module-level documentation](index.html) for more information.
|
||||
#[derive(Clone, Default, PartialOrd, Serialize, Deserialize)]
|
||||
#[derive(Clone, Default, PartialOrd, Deserialize)]
|
||||
pub struct Chunk {
|
||||
pub name: Option<DustString>,
|
||||
pub r#type: FunctionType,
|
||||
@ -114,3 +115,28 @@ impl PartialEq for Chunk {
|
||||
&& self.prototypes == other.prototypes
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for Chunk {
|
||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||
let mut state = serializer.serialize_struct("Chunk", 11)?;
|
||||
|
||||
state.serialize_field("name", &self.name)?;
|
||||
state.serialize_field("boolean_register_count", &self.boolean_register_count)?;
|
||||
state.serialize_field("byte_register_count", &self.byte_register_count)?;
|
||||
state.serialize_field("character_register_count", &self.character_register_count)?;
|
||||
state.serialize_field("float_register_count", &self.float_register_count)?;
|
||||
state.serialize_field("integer_register_count", &self.integer_register_count)?;
|
||||
state.serialize_field("string_register_count", &self.string_register_count)?;
|
||||
state.serialize_field("list_register_count", &self.list_register_count)?;
|
||||
state.serialize_field("function_register_count", &self.function_register_count)?;
|
||||
state.serialize_field("prototype_index", &self.prototype_index)?;
|
||||
state.serialize_field("instructions", &self.instructions)?;
|
||||
state.serialize_field("positions", &self.positions)?;
|
||||
state.serialize_field("prototypes", &self.prototypes)?;
|
||||
state.serialize_field("locals", &self.locals)?;
|
||||
state.serialize_field("constants", &self.constants)?;
|
||||
state.serialize_field("type", &self.r#type)?;
|
||||
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
@ -159,11 +159,7 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
Ok(Compiler {
|
||||
function_name,
|
||||
r#type: FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters: Vec::with_capacity(0),
|
||||
return_type: Type::None,
|
||||
},
|
||||
r#type: FunctionType::default(),
|
||||
instructions: Vec::new(),
|
||||
constants: Vec::new(),
|
||||
locals: Vec::new(),
|
||||
@ -268,12 +264,14 @@ impl<'src> Compiler<'src> {
|
||||
self.instructions
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|(instruction, r#type, _)| {
|
||||
if instruction.b_type() == TypeCode::BOOLEAN && instruction.yields_value() {
|
||||
Some(instruction.a_field() + 1)
|
||||
} else {
|
||||
None
|
||||
.find_map(|(instruction, _, _)| {
|
||||
if instruction.operation() == Operation::LOAD_ENCODED
|
||||
&& instruction.b_type() == TypeCode::BOOLEAN
|
||||
{
|
||||
return Some(instruction.a_field() + 1);
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
.unwrap_or(self.minimum_boolean_register)
|
||||
}
|
||||
@ -283,15 +281,13 @@ impl<'src> Compiler<'src> {
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|(instruction, _, _)| {
|
||||
if instruction.operation() == Operation::LOAD_ENCODED {
|
||||
if instruction.b_type() == TypeCode::BYTE {
|
||||
Some(instruction.a_field() + 1)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
if instruction.operation() == Operation::LOAD_ENCODED
|
||||
&& instruction.b_type() == TypeCode::BYTE
|
||||
{
|
||||
return Some(instruction.a_field() + 1);
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
.unwrap_or(self.minimum_byte_register)
|
||||
}
|
||||
@ -332,7 +328,9 @@ impl<'src> Compiler<'src> {
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|(instruction, r#type, _)| {
|
||||
if r#type == &Type::Integer {
|
||||
if r#type == &Type::Integer
|
||||
|| (instruction.b_type() == TypeCode::INTEGER && instruction.yields_value())
|
||||
{
|
||||
Some(instruction.a_field() + 1)
|
||||
} else {
|
||||
None
|
||||
@ -346,9 +344,8 @@ impl<'src> Compiler<'src> {
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|(instruction, r#type, _)| {
|
||||
if instruction.b_type() == TypeCode::STRING
|
||||
&& r#type == &Type::String
|
||||
&& instruction.yields_value()
|
||||
if r#type == &Type::String
|
||||
|| (instruction.b_type() == TypeCode::STRING && instruction.yields_value())
|
||||
{
|
||||
Some(instruction.a_field() + 1)
|
||||
} else {
|
||||
@ -363,7 +360,7 @@ impl<'src> Compiler<'src> {
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|(instruction, r#type, _)| {
|
||||
if let Type::List(_) = r#type {
|
||||
if let Type::List { .. } = r#type {
|
||||
if instruction.yields_value() {
|
||||
Some(instruction.a_field() + 1)
|
||||
} else {
|
||||
@ -546,7 +543,7 @@ impl<'src> Compiler<'src> {
|
||||
///
|
||||
/// If [`Self::type`] is already set, it will check if the given [Type] is compatible.
|
||||
fn update_return_type(&mut self, new_return_type: Type) -> Result<(), CompileError> {
|
||||
if self.r#type.return_type != Type::None {
|
||||
if self.r#type.return_type.as_ref() != &Type::None {
|
||||
self.r#type
|
||||
.return_type
|
||||
.check(&new_return_type)
|
||||
@ -556,7 +553,7 @@ impl<'src> Compiler<'src> {
|
||||
})?;
|
||||
}
|
||||
|
||||
self.r#type.return_type = new_return_type;
|
||||
*self.r#type.return_type.as_mut() = new_return_type;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -900,7 +897,7 @@ impl<'src> Compiler<'src> {
|
||||
match left_type {
|
||||
Type::Boolean => self.next_boolean_register(),
|
||||
Type::Byte => self.next_byte_register(),
|
||||
Type::Character => self.next_character_register(),
|
||||
Type::Character => self.next_string_register(),
|
||||
Type::Float => self.next_float_register(),
|
||||
Type::Integer => self.next_integer_register(),
|
||||
Type::String => self.next_string_register(),
|
||||
@ -1274,7 +1271,7 @@ impl<'src> Compiler<'src> {
|
||||
if used_boolean_registers > 1 {
|
||||
let close = Instruction::close(
|
||||
next_boolean_register,
|
||||
next_boolean_register + used_boolean_registers,
|
||||
self.next_boolean_register() - 2,
|
||||
TypeCode::BOOLEAN,
|
||||
);
|
||||
|
||||
@ -1282,12 +1279,12 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
}
|
||||
Type::Byte => {
|
||||
let used_byte_registers = self.next_byte_register() - 1 - next_byte_register;
|
||||
let used_byte_registers = self.next_byte_register() - next_byte_register;
|
||||
|
||||
if used_byte_registers > 1 {
|
||||
let close = Instruction::close(
|
||||
next_byte_register,
|
||||
next_byte_register + used_byte_registers,
|
||||
self.next_byte_register() - 2,
|
||||
TypeCode::BYTE,
|
||||
);
|
||||
|
||||
@ -1296,12 +1293,12 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
Type::Character => {
|
||||
let used_character_registers =
|
||||
self.next_character_register() - 1 - next_character_register;
|
||||
self.next_character_register() - next_character_register;
|
||||
|
||||
if used_character_registers > 1 {
|
||||
let close = Instruction::close(
|
||||
next_character_register,
|
||||
next_character_register + used_character_registers,
|
||||
self.next_character_register() - 2,
|
||||
TypeCode::CHARACTER,
|
||||
);
|
||||
|
||||
@ -1309,12 +1306,12 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
}
|
||||
Type::Float => {
|
||||
let used_float_registers = self.next_float_register() - 1 - next_float_register;
|
||||
let used_float_registers = self.next_float_register() - next_float_register;
|
||||
|
||||
if used_float_registers > 1 {
|
||||
let close = Instruction::close(
|
||||
next_float_register,
|
||||
next_float_register + used_float_registers,
|
||||
self.next_float_register() - 2,
|
||||
TypeCode::FLOAT,
|
||||
);
|
||||
|
||||
@ -1323,12 +1320,12 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
Type::Integer => {
|
||||
let used_integer_registers =
|
||||
self.next_integer_register() - 1 - next_integer_register;
|
||||
self.next_integer_register() - next_integer_register;
|
||||
|
||||
if used_integer_registers > 1 {
|
||||
let close = Instruction::close(
|
||||
next_integer_register,
|
||||
next_integer_register + used_integer_registers,
|
||||
self.next_integer_register() - 2,
|
||||
TypeCode::INTEGER,
|
||||
);
|
||||
|
||||
@ -1336,20 +1333,19 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
}
|
||||
Type::String => {
|
||||
let used_string_registers =
|
||||
self.next_string_register() - 1 - next_string_register;
|
||||
let used_string_registers = self.next_string_register() - next_string_register;
|
||||
|
||||
if used_string_registers > 1 {
|
||||
let close = Instruction::close(
|
||||
next_string_register,
|
||||
next_string_register + used_string_registers,
|
||||
self.next_string_register() - 2,
|
||||
TypeCode::STRING,
|
||||
);
|
||||
|
||||
self.emit_instruction(close, Type::None, self.current_position);
|
||||
}
|
||||
}
|
||||
Type::List(_) => {
|
||||
Type::List { .. } => {
|
||||
let used_list_registers = self.next_list_register() - next_list_register;
|
||||
|
||||
if used_list_registers > 1 {
|
||||
@ -1374,7 +1370,7 @@ impl<'src> Compiler<'src> {
|
||||
Type::Float => self.next_float_register().saturating_sub(1),
|
||||
Type::Integer => self.next_integer_register().saturating_sub(1),
|
||||
Type::String => self.next_string_register().saturating_sub(1),
|
||||
Type::List(_) => self.next_list_register().saturating_sub(1),
|
||||
Type::List { .. } => self.next_list_register().saturating_sub(1),
|
||||
_ => todo!(),
|
||||
};
|
||||
let destination = self.next_list_register();
|
||||
@ -1595,7 +1591,7 @@ impl<'src> Compiler<'src> {
|
||||
}
|
||||
|
||||
let end = self.previous_position.1;
|
||||
let destination = match function.r#type().return_type {
|
||||
let destination = match function.r#type().return_type.as_ref() {
|
||||
Type::Boolean => self.next_boolean_register(),
|
||||
Type::Byte => self.next_byte_register(),
|
||||
Type::Character => self.next_character_register(),
|
||||
@ -1605,7 +1601,7 @@ impl<'src> Compiler<'src> {
|
||||
Type::None => 0,
|
||||
_ => todo!(),
|
||||
};
|
||||
let return_type = function.r#type().return_type;
|
||||
let return_type = *function.r#type().return_type;
|
||||
let call_native = Instruction::from(CallNative {
|
||||
destination,
|
||||
function,
|
||||
@ -1865,7 +1861,7 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
function_compiler.prototype_index = self.prototypes.len() as u16;
|
||||
|
||||
let mut value_parameters: Vec<(u16, Type)> = Vec::with_capacity(3);
|
||||
let mut value_parameters = Vec::with_capacity(3);
|
||||
|
||||
while !function_compiler.allow(Token::RightParenthesis)? {
|
||||
let is_mutable = function_compiler.allow(Token::Mut)?;
|
||||
@ -1899,7 +1895,7 @@ impl<'src> Compiler<'src> {
|
||||
Type::String => function_compiler.next_string_register(),
|
||||
_ => todo!(),
|
||||
};
|
||||
let (_, identifier_index) = function_compiler.declare_local(
|
||||
function_compiler.declare_local(
|
||||
parameter,
|
||||
local_register_index,
|
||||
r#type.clone(),
|
||||
@ -1917,7 +1913,7 @@ impl<'src> Compiler<'src> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
value_parameters.push((identifier_index, r#type));
|
||||
value_parameters.push(r#type);
|
||||
function_compiler.allow(Token::Comma)?;
|
||||
}
|
||||
|
||||
@ -1933,11 +1929,7 @@ impl<'src> Compiler<'src> {
|
||||
} else {
|
||||
Type::None
|
||||
};
|
||||
let function_type = FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters,
|
||||
return_type,
|
||||
};
|
||||
let function_type = FunctionType::new([], value_parameters, return_type);
|
||||
|
||||
function_compiler.r#type = function_type.clone();
|
||||
|
||||
@ -1963,7 +1955,7 @@ impl<'src> Compiler<'src> {
|
||||
self.declare_local(
|
||||
identifier,
|
||||
destination,
|
||||
Type::function(function_type.clone()),
|
||||
Type::Function(function_type.clone()),
|
||||
false,
|
||||
self.current_scope,
|
||||
);
|
||||
@ -1973,7 +1965,7 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
self.emit_instruction(
|
||||
load_function,
|
||||
Type::function(function_type),
|
||||
Type::Function(function_type),
|
||||
Span(function_start, function_end),
|
||||
);
|
||||
|
||||
@ -1995,7 +1987,7 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
if !matches!(
|
||||
last_instruction_type,
|
||||
Type::Function(_) | Type::SelfFunction
|
||||
Type::Function { .. } | Type::SelfFunction
|
||||
) {
|
||||
return Err(CompileError::ExpectedFunction {
|
||||
found: self.previous_token.to_owned(),
|
||||
@ -2006,8 +1998,8 @@ impl<'src> Compiler<'src> {
|
||||
|
||||
let function_register = last_instruction.a_field();
|
||||
let function_return_type = match last_instruction_type {
|
||||
Type::Function(function_type) => function_type.return_type.clone(),
|
||||
Type::SelfFunction => self.r#type.return_type.clone(),
|
||||
Type::Function(function_type) => *function_type.return_type.clone(),
|
||||
Type::SelfFunction => *self.r#type.return_type.clone(),
|
||||
_ => {
|
||||
return Err(CompileError::ExpectedFunction {
|
||||
found: self.previous_token.to_owned(),
|
||||
|
@ -597,7 +597,8 @@ impl Instruction {
|
||||
|
||||
function.returns_value()
|
||||
}
|
||||
Operation::EQUAL
|
||||
Operation::CLOSE
|
||||
| Operation::EQUAL
|
||||
| Operation::LESS
|
||||
| Operation::LESS_EQUAL
|
||||
| Operation::TEST
|
||||
|
@ -74,7 +74,7 @@ macro_rules! define_native_function {
|
||||
pub fn returns_value(&self) -> bool {
|
||||
match self {
|
||||
$(
|
||||
NativeFunction::$name => $type.return_type != Type::None,
|
||||
NativeFunction::$name => $type.return_type.as_ref() != &Type::None,
|
||||
)*
|
||||
}
|
||||
}
|
||||
@ -134,11 +134,7 @@ define_native_function! {
|
||||
Panic,
|
||||
3,
|
||||
"panic",
|
||||
FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters: Vec::with_capacity(0),
|
||||
return_type: Type::None
|
||||
},
|
||||
FunctionType::new([], [], Type::None),
|
||||
assert::panic
|
||||
),
|
||||
|
||||
@ -151,11 +147,7 @@ define_native_function! {
|
||||
ToString,
|
||||
8,
|
||||
"to_string",
|
||||
FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters: vec![(0, Type::Any)],
|
||||
return_type: Type::String
|
||||
},
|
||||
FunctionType::new([], [Type::Any], Type::String),
|
||||
string::to_string
|
||||
),
|
||||
|
||||
@ -212,11 +204,7 @@ define_native_function! {
|
||||
ReadLine,
|
||||
50,
|
||||
"read_line",
|
||||
FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters: Vec::with_capacity(0),
|
||||
return_type: Type::String
|
||||
},
|
||||
FunctionType::new([], [], Type::String),
|
||||
io::read_line
|
||||
),
|
||||
// (ReadTo, 51_u8, "read_to", false),
|
||||
@ -228,11 +216,7 @@ define_native_function! {
|
||||
Write,
|
||||
55,
|
||||
"write",
|
||||
FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters: vec![(0, Type::String)],
|
||||
return_type: Type::None
|
||||
},
|
||||
FunctionType::new([], [Type::Any], Type::None),
|
||||
io::write
|
||||
),
|
||||
// (WriteFile, 56_u8, "write_file", false),
|
||||
@ -240,11 +224,7 @@ define_native_function! {
|
||||
WriteLine,
|
||||
57,
|
||||
"write_line",
|
||||
FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters: vec![(0, Type::String)],
|
||||
return_type: Type::None
|
||||
},
|
||||
FunctionType::new([], [Type::Any], Type::None),
|
||||
io::write_line
|
||||
),
|
||||
|
||||
@ -253,11 +233,7 @@ define_native_function! {
|
||||
RandomInteger,
|
||||
58,
|
||||
"random_int",
|
||||
FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters: vec![(0, Type::Integer), (1, Type::Integer)],
|
||||
return_type: Type::Integer
|
||||
},
|
||||
FunctionType::new([], [Type::Integer, Type::Integer], Type::Integer),
|
||||
random::random_int
|
||||
),
|
||||
|
||||
@ -266,20 +242,7 @@ define_native_function! {
|
||||
Spawn,
|
||||
60,
|
||||
"spawn",
|
||||
FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters: vec![
|
||||
(
|
||||
0,
|
||||
Type::Function(Box::new(FunctionType {
|
||||
type_parameters: Vec::with_capacity(0),
|
||||
value_parameters: Vec::with_capacity(0),
|
||||
return_type: Type::Any
|
||||
}))
|
||||
)
|
||||
],
|
||||
return_type: Type::None
|
||||
},
|
||||
FunctionType::new([], [ Type::function([], [], Type::Any)], Type::None),
|
||||
thread::spawn
|
||||
)
|
||||
}
|
||||
|
@ -10,7 +10,8 @@ use serde::{Deserialize, Serialize};
|
||||
use crate::instruction::TypeCode;
|
||||
|
||||
/// Description of a kind of value.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[derive(Clone, Default, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(tag = "Type", content = "Value")]
|
||||
pub enum Type {
|
||||
Any,
|
||||
Boolean,
|
||||
@ -18,31 +19,31 @@ pub enum Type {
|
||||
Character,
|
||||
Enum(EnumType),
|
||||
Float,
|
||||
Function(Box<FunctionType>),
|
||||
Generic {
|
||||
identifier_index: u8,
|
||||
concrete_type: Option<Box<Type>>,
|
||||
},
|
||||
Function(FunctionType),
|
||||
Generic(GenericType),
|
||||
Integer,
|
||||
List(TypeCode),
|
||||
Map {
|
||||
pairs: Vec<(u8, Type)>,
|
||||
},
|
||||
Map(Vec<Type>),
|
||||
#[default]
|
||||
None,
|
||||
Range {
|
||||
r#type: Box<Type>,
|
||||
},
|
||||
Range(Box<Type>),
|
||||
SelfFunction,
|
||||
String,
|
||||
Struct(StructType),
|
||||
Tuple {
|
||||
fields: Vec<Type>,
|
||||
},
|
||||
Tuple(Vec<Type>),
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub fn function(function_type: FunctionType) -> Self {
|
||||
Type::Function(Box::new(function_type))
|
||||
pub fn function<T: Into<Vec<u16>>, U: Into<Vec<Type>>>(
|
||||
type_parameters: T,
|
||||
value_parameters: U,
|
||||
return_type: Type,
|
||||
) -> Self {
|
||||
Type::Function(FunctionType {
|
||||
type_parameters: type_parameters.into(),
|
||||
value_parameters: value_parameters.into(),
|
||||
return_type: Box::new(return_type),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn type_code(&self) -> TypeCode {
|
||||
@ -54,18 +55,18 @@ impl Type {
|
||||
Type::Integer => TypeCode::INTEGER,
|
||||
Type::None => TypeCode::NONE,
|
||||
Type::String => TypeCode::STRING,
|
||||
Type::List(_) => TypeCode::LIST,
|
||||
Type::Function(_) => TypeCode::FUNCTION,
|
||||
Type::List { .. } => TypeCode::LIST,
|
||||
Type::Function { .. } => TypeCode::FUNCTION,
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a concrete type, either the type itself or the concrete type of a generic type.
|
||||
pub fn concrete_type(&self) -> &Type {
|
||||
if let Type::Generic {
|
||||
if let Type::Generic(GenericType {
|
||||
concrete_type: Some(concrete_type),
|
||||
..
|
||||
} = self
|
||||
}) = self
|
||||
{
|
||||
concrete_type.concrete_type()
|
||||
} else {
|
||||
@ -86,14 +87,14 @@ impl Type {
|
||||
| (Type::None, Type::None)
|
||||
| (Type::String { .. }, Type::String { .. }) => return Ok(()),
|
||||
(
|
||||
Type::Generic {
|
||||
Type::Generic(GenericType {
|
||||
concrete_type: left,
|
||||
..
|
||||
},
|
||||
Type::Generic {
|
||||
}),
|
||||
Type::Generic(GenericType {
|
||||
concrete_type: right,
|
||||
..
|
||||
},
|
||||
}),
|
||||
) => match (left, right) {
|
||||
(Some(left), Some(right)) => {
|
||||
if left.check(right).is_ok() {
|
||||
@ -105,8 +106,8 @@ impl Type {
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
(Type::Generic { concrete_type, .. }, other)
|
||||
| (other, Type::Generic { concrete_type, .. }) => {
|
||||
(Type::Generic(GenericType { concrete_type, .. }), other)
|
||||
| (other, Type::Generic(GenericType { concrete_type, .. })) => {
|
||||
if let Some(concrete_type) = concrete_type {
|
||||
if other == concrete_type.as_ref() {
|
||||
return Ok(());
|
||||
@ -133,12 +134,12 @@ impl Type {
|
||||
type_parameters: left_type_parameters,
|
||||
value_parameters: left_value_parameters,
|
||||
return_type: left_return,
|
||||
} = left_function_type.as_ref();
|
||||
} = left_function_type;
|
||||
let FunctionType {
|
||||
type_parameters: right_type_parameters,
|
||||
value_parameters: right_value_parameters,
|
||||
return_type: right_return,
|
||||
} = right_function_type.as_ref();
|
||||
} = right_function_type;
|
||||
|
||||
if left_return != right_return
|
||||
|| left_type_parameters != right_type_parameters
|
||||
@ -152,7 +153,7 @@ impl Type {
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
(Type::Range { r#type: left_type }, Type::Range { r#type: right_type }) => {
|
||||
(Type::Range(left_type), Type::Range(right_type)) => {
|
||||
if left_type == right_type {
|
||||
return Ok(());
|
||||
}
|
||||
@ -177,25 +178,24 @@ impl Display for Type {
|
||||
Type::Enum(EnumType { name, .. }) => write!(f, "{name}"),
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Function(function_type) => write!(f, "{function_type}"),
|
||||
Type::Generic { concrete_type, .. } => {
|
||||
Type::Generic(GenericType { concrete_type, .. }) => {
|
||||
match concrete_type.clone().map(|r#box| *r#box) {
|
||||
Some(Type::Generic {
|
||||
identifier_index: identifier,
|
||||
..
|
||||
}) => write!(f, "{identifier}"),
|
||||
Some(Type::Generic(GenericType {
|
||||
identifier_index, ..
|
||||
})) => write!(f, "C_{identifier_index}"),
|
||||
Some(concrete_type) => write!(f, "implied to be {concrete_type}"),
|
||||
None => write!(f, "unknown"),
|
||||
}
|
||||
}
|
||||
Type::Integer => write!(f, "int"),
|
||||
Type::List(item_type) => write!(f, "[{item_type}]"),
|
||||
Type::Map { pairs } => {
|
||||
Type::Map(pairs) => {
|
||||
write!(f, "map ")?;
|
||||
|
||||
write!(f, "{{")?;
|
||||
|
||||
for (index, (key, value)) in pairs.iter().enumerate() {
|
||||
write!(f, "{key}: {value}")?;
|
||||
for (index, r#type) in pairs.iter().enumerate() {
|
||||
write!(f, "???: {type}")?;
|
||||
|
||||
if index != pairs.len() - 1 {
|
||||
write!(f, ", ")?;
|
||||
@ -205,11 +205,11 @@ impl Display for Type {
|
||||
write!(f, "}}")
|
||||
}
|
||||
Type::None => write!(f, "none"),
|
||||
Type::Range { r#type } => write!(f, "{type} range"),
|
||||
Type::Range(r#type) => write!(f, "{type} range"),
|
||||
Type::SelfFunction => write!(f, "self"),
|
||||
Type::String => write!(f, "str"),
|
||||
Type::Struct(struct_type) => write!(f, "{struct_type}"),
|
||||
Type::Tuple { fields } => {
|
||||
Type::Tuple(fields) => {
|
||||
write!(f, "(")?;
|
||||
|
||||
for (index, r#type) in fields.iter().enumerate() {
|
||||
@ -244,13 +244,13 @@ impl Ord for Type {
|
||||
(Type::Character, Type::Character) => Ordering::Equal,
|
||||
(Type::Character, _) => Ordering::Greater,
|
||||
(Type::Enum(left_enum), Type::Enum(right_enum)) => left_enum.cmp(right_enum),
|
||||
(Type::Enum(_), _) => Ordering::Greater,
|
||||
(Type::Enum { .. }, _) => Ordering::Greater,
|
||||
(Type::Float, Type::Float) => Ordering::Equal,
|
||||
(Type::Float, _) => Ordering::Greater,
|
||||
(Type::Function(left_function), Type::Function(right_function)) => {
|
||||
left_function.cmp(right_function)
|
||||
}
|
||||
(Type::Function(_), _) => Ordering::Greater,
|
||||
(Type::Function { .. }, _) => Ordering::Greater,
|
||||
(Type::Generic { .. }, Type::Generic { .. }) => Ordering::Equal,
|
||||
(Type::Generic { .. }, _) => Ordering::Greater,
|
||||
(Type::Integer, Type::Integer) => Ordering::Equal,
|
||||
@ -259,15 +259,13 @@ impl Ord for Type {
|
||||
left_item_type.cmp(right_item_type)
|
||||
}
|
||||
(Type::List { .. }, _) => Ordering::Greater,
|
||||
(Type::Map { pairs: left_pairs }, Type::Map { pairs: right_pairs }) => {
|
||||
(Type::Map(left_pairs), Type::Map(right_pairs)) => {
|
||||
left_pairs.iter().cmp(right_pairs.iter())
|
||||
}
|
||||
(Type::Map { .. }, _) => Ordering::Greater,
|
||||
(Type::None, Type::None) => Ordering::Equal,
|
||||
(Type::None, _) => Ordering::Greater,
|
||||
(Type::Range { r#type: left_type }, Type::Range { r#type: right_type }) => {
|
||||
left_type.cmp(right_type)
|
||||
}
|
||||
(Type::Range(left_type), Type::Range(right_type)) => left_type.cmp(right_type),
|
||||
(Type::Range { .. }, _) => Ordering::Greater,
|
||||
(Type::SelfFunction, Type::SelfFunction) => Ordering::Equal,
|
||||
(Type::SelfFunction, _) => Ordering::Greater,
|
||||
@ -276,9 +274,9 @@ impl Ord for Type {
|
||||
(Type::Struct(left_struct), Type::Struct(right_struct)) => {
|
||||
left_struct.cmp(right_struct)
|
||||
}
|
||||
(Type::Struct(_), _) => Ordering::Greater,
|
||||
(Type::Struct { .. }, _) => Ordering::Greater,
|
||||
|
||||
(Type::Tuple { fields: left }, Type::Tuple { fields: right }) => left.cmp(right),
|
||||
(Type::Tuple(left), Type::Tuple(right)) => left.cmp(right),
|
||||
(Type::Tuple { .. }, _) => Ordering::Greater,
|
||||
}
|
||||
}
|
||||
@ -287,12 +285,12 @@ impl Ord for Type {
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct FunctionType {
|
||||
pub type_parameters: Vec<u16>,
|
||||
pub value_parameters: Vec<(u16, Type)>,
|
||||
pub return_type: Type,
|
||||
pub value_parameters: Vec<Type>,
|
||||
pub return_type: Box<Type>,
|
||||
}
|
||||
|
||||
impl FunctionType {
|
||||
pub fn new<T: Into<Vec<u16>>, U: Into<Vec<(u16, Type)>>>(
|
||||
pub fn new<T: Into<Vec<u16>>, U: Into<Vec<Type>>>(
|
||||
type_parameters: T,
|
||||
value_parameters: U,
|
||||
return_type: Type,
|
||||
@ -300,7 +298,7 @@ impl FunctionType {
|
||||
FunctionType {
|
||||
type_parameters: type_parameters.into(),
|
||||
value_parameters: value_parameters.into(),
|
||||
return_type,
|
||||
return_type: Box::new(return_type),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,7 +308,7 @@ impl Default for FunctionType {
|
||||
FunctionType {
|
||||
type_parameters: Vec::new(),
|
||||
value_parameters: Vec::new(),
|
||||
return_type: Type::None,
|
||||
return_type: Box::new(Type::None),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -336,7 +334,7 @@ impl Display for FunctionType {
|
||||
write!(f, "(")?;
|
||||
|
||||
if !self.value_parameters.is_empty() {
|
||||
for (index, (_, r#type)) in self.value_parameters.iter().enumerate() {
|
||||
for (index, r#type) in self.value_parameters.iter().enumerate() {
|
||||
if index > 0 {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
@ -347,7 +345,7 @@ impl Display for FunctionType {
|
||||
|
||||
write!(f, ")")?;
|
||||
|
||||
if self.return_type != Type::None {
|
||||
if self.return_type.as_ref() != &Type::None {
|
||||
write!(f, " -> {}", self.return_type)?;
|
||||
}
|
||||
|
||||
@ -491,6 +489,12 @@ impl Display for EnumType {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct GenericType {
|
||||
pub identifier_index: u8,
|
||||
pub concrete_type: Option<Box<Type>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TypeConflict {
|
||||
pub expected: Type,
|
||||
|
@ -11,6 +11,7 @@ use super::RangeValue;
|
||||
pub type DustString = SmartString<LazyCompact>;
|
||||
|
||||
#[derive(Debug, PartialEq, PartialOrd, Serialize, Deserialize)]
|
||||
#[serde(tag = "type", content = "value")]
|
||||
pub enum ConcreteValue {
|
||||
Boolean(bool),
|
||||
Byte(u8),
|
||||
|
@ -50,6 +50,14 @@ impl Value {
|
||||
Value::Concrete(ConcreteValue::String(string.into()))
|
||||
}
|
||||
|
||||
pub fn as_concrete(&self) -> Option<&ConcreteValue> {
|
||||
if let Value::Concrete(concrete_value) = self {
|
||||
Some(concrete_value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_boolean(&self) -> Option<bool> {
|
||||
if let Value::Concrete(ConcreteValue::Boolean(boolean)) = self {
|
||||
Some(*boolean)
|
||||
@ -118,7 +126,7 @@ impl Value {
|
||||
match self {
|
||||
Value::Concrete(concrete_value) => concrete_value.r#type(),
|
||||
Value::AbstractList(AbstractList { item_type, .. }) => Type::List(*item_type),
|
||||
Value::Function(Function { r#type, .. }) => Type::Function(Box::new(r#type.clone())),
|
||||
Value::Function(Function { r#type, .. }) => Type::Function(r#type.clone()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,9 +32,7 @@ impl RangeValue {
|
||||
}
|
||||
};
|
||||
|
||||
Type::Range {
|
||||
r#type: Box::new(inner_type),
|
||||
}
|
||||
Type::Range(Box::new(inner_type))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,7 @@ use dust_lang::{
|
||||
fn add_bytes() {
|
||||
let source = "0x28 + 0x02";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::Byte,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::Byte),
|
||||
instructions: vec![
|
||||
Instruction::load_encoded(0, 40, TypeCode::BYTE, false),
|
||||
Instruction::load_encoded(1, 2, TypeCode::BYTE, false),
|
||||
@ -34,10 +31,7 @@ fn add_bytes() {
|
||||
fn add_characters() {
|
||||
let source = "'a' + 'b'";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::String,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::String),
|
||||
instructions: vec![
|
||||
Instruction::add(
|
||||
0,
|
||||
@ -60,10 +54,7 @@ fn add_characters() {
|
||||
fn add_floats() {
|
||||
let source = "2.40 + 40.02";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::Float,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::Float),
|
||||
instructions: vec![
|
||||
Instruction::add(
|
||||
0,
|
||||
@ -86,10 +77,7 @@ fn add_floats() {
|
||||
fn add_integers() {
|
||||
let source = "40 + 2";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::Integer,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::Integer),
|
||||
instructions: vec![
|
||||
Instruction::add(
|
||||
0,
|
||||
@ -112,10 +100,7 @@ fn add_integers() {
|
||||
fn add_strings() {
|
||||
let source = "\"Hello, \" + \"World!\"";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::String,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::String),
|
||||
instructions: vec![
|
||||
Instruction::add(
|
||||
0,
|
||||
|
@ -7,10 +7,7 @@ use dust_lang::{
|
||||
fn load_boolean_true() {
|
||||
let source = "true";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::Boolean,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::Boolean),
|
||||
instructions: vec![
|
||||
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
|
||||
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||
@ -28,10 +25,7 @@ fn load_boolean_true() {
|
||||
fn load_boolean_false() {
|
||||
let source = "false";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::Boolean,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::Boolean),
|
||||
instructions: vec![
|
||||
Instruction::load_encoded(0, false as u8, TypeCode::BOOLEAN, false),
|
||||
Instruction::r#return(true, 0, TypeCode::BOOLEAN),
|
||||
@ -49,10 +43,7 @@ fn load_boolean_false() {
|
||||
fn load_byte() {
|
||||
let source = "0x2a";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::Byte,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::Byte),
|
||||
instructions: vec![
|
||||
Instruction::load_encoded(0, 0x2a, TypeCode::BYTE, false),
|
||||
Instruction::r#return(true, 0, TypeCode::BYTE),
|
||||
@ -70,10 +61,7 @@ fn load_byte() {
|
||||
fn load_character() {
|
||||
let source = "'a'";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::Character,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::Character),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::CHARACTER, false),
|
||||
Instruction::r#return(true, 0, TypeCode::CHARACTER),
|
||||
@ -92,10 +80,7 @@ fn load_character() {
|
||||
fn load_float() {
|
||||
let source = "42.42";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::Float,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::Float),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::FLOAT, false),
|
||||
Instruction::r#return(true, 0, TypeCode::FLOAT),
|
||||
@ -114,10 +99,7 @@ fn load_float() {
|
||||
fn load_integer() {
|
||||
let source = "42";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::Integer,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::Integer),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
|
||||
Instruction::r#return(true, 0, TypeCode::INTEGER),
|
||||
@ -136,10 +118,7 @@ fn load_integer() {
|
||||
fn load_string() {
|
||||
let source = "\"Hello, World!\"";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::String,
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::String),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::STRING, false),
|
||||
Instruction::r#return(true, 0, TypeCode::STRING),
|
||||
@ -158,10 +137,7 @@ fn load_string() {
|
||||
fn load_boolean_list() {
|
||||
let source = "[true, false]";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::List(TypeCode::BOOLEAN),
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::List(TypeCode::BOOLEAN)),
|
||||
instructions: vec![
|
||||
Instruction::load_encoded(0, true as u8, TypeCode::BOOLEAN, false),
|
||||
Instruction::load_encoded(1, false as u8, TypeCode::BOOLEAN, false),
|
||||
@ -184,10 +160,7 @@ fn load_boolean_list() {
|
||||
fn load_byte_list() {
|
||||
let source = "[0x2a, 0x42]";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::List(TypeCode::BYTE),
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::List(TypeCode::BYTE)),
|
||||
instructions: vec![
|
||||
Instruction::load_encoded(0, 0x2a, TypeCode::BYTE, false),
|
||||
Instruction::load_encoded(1, 0x42, TypeCode::BYTE, false),
|
||||
@ -210,10 +183,7 @@ fn load_byte_list() {
|
||||
fn load_character_list() {
|
||||
let source = "['a', 'b']";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::List(TypeCode::CHARACTER),
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::List(TypeCode::CHARACTER)),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::CHARACTER, false),
|
||||
Instruction::load_constant(1, 1, TypeCode::CHARACTER, false),
|
||||
@ -237,10 +207,7 @@ fn load_character_list() {
|
||||
fn load_float_list() {
|
||||
let source = "[42.42, 24.24]";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::List(TypeCode::FLOAT),
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::List(TypeCode::FLOAT)),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::FLOAT, false),
|
||||
Instruction::load_constant(1, 1, TypeCode::FLOAT, false),
|
||||
@ -264,10 +231,7 @@ fn load_float_list() {
|
||||
fn load_integer_list() {
|
||||
let source = "[1, 2, 3]";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::List(TypeCode::INTEGER),
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::List(TypeCode::INTEGER)),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
|
||||
Instruction::load_constant(1, 1, TypeCode::INTEGER, false),
|
||||
@ -297,10 +261,7 @@ fn load_integer_list() {
|
||||
fn load_string_list() {
|
||||
let source = "[\"Hello\", \"World\"]";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::List(TypeCode::STRING),
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::List(TypeCode::STRING)),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::STRING, false),
|
||||
Instruction::load_constant(1, 1, TypeCode::STRING, false),
|
||||
@ -327,10 +288,7 @@ fn load_string_list() {
|
||||
fn load_nested_list() {
|
||||
let source = "[[1, 2], [3, 4]]";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::List(TypeCode::LIST),
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::List(TypeCode::LIST)),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
|
||||
Instruction::load_constant(1, 1, TypeCode::INTEGER, false),
|
||||
@ -372,10 +330,7 @@ fn load_nested_list() {
|
||||
fn load_deeply_nested_list() {
|
||||
let source = "[[[1, 2], [3, 4]], [[5, 6], [7, 8]]]";
|
||||
let chunk = Chunk {
|
||||
r#type: FunctionType {
|
||||
return_type: Type::List(TypeCode::LIST),
|
||||
..FunctionType::default()
|
||||
},
|
||||
r#type: FunctionType::new([], [], Type::List(TypeCode::LIST)),
|
||||
instructions: vec![
|
||||
Instruction::load_constant(0, 0, TypeCode::INTEGER, false),
|
||||
Instruction::load_constant(1, 1, TypeCode::INTEGER, false),
|
||||
|
Loading…
x
Reference in New Issue
Block a user