This commit is contained in:
Andrew Morris
2023-03-04 22:11:38 +11:00
parent d046ff8c3c
commit a71e92730d
3 changed files with 495 additions and 37 deletions

View File

@@ -0,0 +1,369 @@
use std::collections::HashMap;
use crate::assembly_ast::{
Array, Assembly, Class, Definition, DefinitionContent, DefinitionRef, Function, Instruction,
InstructionOrLabel, Label, LabelRef, Object, Register, Value,
};
pub fn assemble(assembly: &Assembly) -> Vec<u8> {
let mut assembler = Assembler {
output: Vec::new(),
fn_data: Default::default(),
definitions_map: LocationMap {
references: HashMap::new(),
found_locations: HashMap::new(),
},
};
assembler.assembly(assembly);
return assembler.output;
}
struct Assembler {
output: Vec<u8>,
fn_data: AssemblerFnData,
definitions_map: LocationMap,
}
impl Assembler {
fn assembly(&mut self, assembly: &Assembly) {
for definition in &assembly.definitions {
self.definition(definition);
}
self.definitions_map.resolve(&mut self.output);
}
fn definition(&mut self, definition: &Definition) {
self.definitions_map.found_locations.insert(
LocationRef::DefinitionRef(definition.ref_.clone()),
self.output.len(),
);
match &definition.content {
DefinitionContent::Function(function) => {
self.function(function);
}
DefinitionContent::Class(class) => {
self.class(class);
}
DefinitionContent::Value(value) => {
self.value(value);
}
}
}
fn function(&mut self, function: &Function) {
self.output.push(ValueType::Function as u8);
self.fn_data = Default::default();
self.fn_data.register_count_pos = self.output.len();
self.output.push(0xff); // Placeholder for register count
self.output.push(function.parameters.len() as u8);
for parameter in &function.parameters {
self.register(parameter);
}
for instruction_or_label in &function.body {
match instruction_or_label {
InstructionOrLabel::Instruction(instruction) => {
self.instruction(instruction);
}
InstructionOrLabel::Label(label) => {
self.label(label);
}
}
}
self.output.push(Instruction::End.byte());
// TODO: Handle >255 registers
self.output[self.fn_data.register_count_pos] = self.fn_data.register_map.len() as u8;
self.fn_data.labels_map.resolve(&mut self.output);
}
fn class(&mut self, class: &Class) {
self.output.push(ValueType::Class as u8);
self.value(&class.constructor);
self.value(&class.methods);
}
fn label(&mut self, label: &Label) {
self
.fn_data
.labels_map
.found_locations
.insert(LocationRef::LabelRef(label.ref_()), self.output.len());
}
fn instruction(&mut self, instruction: &Instruction) {
use Instruction::*;
self.output.push(instruction.byte());
match instruction {
End => {}
OpInc(dst) | OpDec(dst) => {
self.register(dst);
}
Mov(arg, dst)
| OpNot(arg, dst)
| OpBitNot(arg, dst)
| TypeOf(arg, dst)
| UnaryPlus(arg, dst)
| UnaryMinus(arg, dst) => {
self.value(arg);
self.register(dst);
}
OpPlus(arg1, arg2, dst)
| OpMinus(arg1, arg2, dst)
| OpMul(arg1, arg2, dst)
| OpDiv(arg1, arg2, dst)
| OpMod(arg1, arg2, dst)
| OpExp(arg1, arg2, dst)
| OpEq(arg1, arg2, dst)
| OpNe(arg1, arg2, dst)
| OpTripleEq(arg1, arg2, dst)
| OpTripleNe(arg1, arg2, dst)
| OpAnd(arg1, arg2, dst)
| OpOr(arg1, arg2, dst)
| OpLess(arg1, arg2, dst)
| OpLessEq(arg1, arg2, dst)
| OpGreater(arg1, arg2, dst)
| OpGreaterEq(arg1, arg2, dst)
| OpNullishCoalesce(arg1, arg2, dst)
| OpOptionalChain(arg1, arg2, dst)
| OpBitAnd(arg1, arg2, dst)
| OpBitOr(arg1, arg2, dst)
| OpBitXor(arg1, arg2, dst)
| OpLeftShift(arg1, arg2, dst)
| OpRightShift(arg1, arg2, dst)
| OpRightShiftUnsigned(arg1, arg2, dst)
| InstanceOf(arg1, arg2, dst)
| In(arg1, arg2, dst)
| Call(arg1, arg2, dst)
| Bind(arg1, arg2, dst)
| Sub(arg1, arg2, dst)
| SubMov(arg1, arg2, dst)
| New(arg1, arg2, dst) => {
self.value(arg1);
self.value(arg2);
self.register(dst);
}
Apply(arg1, arg2, arg3, dst) | SubCall(arg1, arg2, arg3, dst) => {
self.value(arg1);
self.value(arg2);
self.value(arg3);
self.register(dst);
}
Jmp(label_ref) => {
self.label_ref(label_ref);
}
JmpIf(value, label_ref) => {
self.value(value);
self.label_ref(label_ref);
}
}
}
fn value(&mut self, value: &Value) {
match value {
Value::Register(register) => {
self.output.push(ValueType::Register as u8);
self.register(register);
}
Value::Number(number) => self.number(*number),
Value::String(string) => self.string(string),
Value::Boolean(boolean) => match boolean {
false => self.output.push(ValueType::False as u8),
true => self.output.push(ValueType::True as u8),
},
Value::Null => self.output.push(ValueType::Null as u8),
Value::Undefined => self.output.push(ValueType::Undefined as u8),
Value::Array(array) => self.array(array),
Value::Object(object) => self.object(object),
Value::DefinitionRef(definition_ref) => self.definition_ref(definition_ref),
}
}
fn label_ref(&mut self, label_ref: &LabelRef) {
self
.fn_data
.labels_map
.add_unresolved(LocationRef::LabelRef(label_ref.clone()), &mut self.output);
}
fn register(&mut self, register: &Register) {
let reg_index = self.lookup_register(register);
self.output.push(reg_index);
}
fn lookup_register(&mut self, register: &Register) -> u8 {
match register {
Register::Return => 0,
Register::This => 1,
Register::Named(_) => match self.fn_data.register_map.get(register) {
Some(index) => *index,
None => {
// TODO: Support >255 registers
let index = (self.fn_data.register_map.len() as u8) + 2;
self.fn_data.register_map.insert(register.clone(), index);
index
}
},
Register::Ignore => 0xff,
}
}
fn varsize_uint(&mut self, value: usize) {
let mut x = value;
loop {
let mut b: u8 = (x % 128) as u8;
x /= 128;
if x != 0 {
b += 128;
}
self.output.push(b);
if x == 0 {
break;
}
}
}
fn number(&mut self, value: f64) {
self.output.push(ValueType::Number as u8);
if value == (value as i8) as f64 {
self.output.push(ValueType::SignedByte as u8);
for b in (value as i8).to_le_bytes() {
self.output.push(b);
}
} else {
self.output.push(ValueType::Number as u8);
for b in value.to_le_bytes() {
self.output.push(b);
}
}
}
fn string(&mut self, value: &String) {
self.output.push(ValueType::String as u8);
self.varsize_uint(value.len());
for b in value.as_bytes() {
self.output.push(*b);
}
}
fn definition_ref(&mut self, value: &DefinitionRef) {
self.output.push(ValueType::Function as u8);
self
.definitions_map
.add_unresolved(LocationRef::DefinitionRef(value.clone()), &mut self.output);
}
fn array(&mut self, array: &Array) {
self.output.push(ValueType::Array as u8);
self.varsize_uint(array.values.len());
for value in &array.values {
self.value(value);
}
}
fn object(&mut self, object: &Object) {
self.output.push(ValueType::Object as u8);
self.varsize_uint(object.properties.len());
for (key, value) in &object.properties {
self.value(key);
self.value(value);
}
}
}
enum ValueType {
End = 0x00,
Void = 0x01,
Undefined = 0x02,
Null = 0x03,
False = 0x04,
True = 0x05,
SignedByte = 0x06,
Number = 0x07,
String = 0x08,
Array = 0x09,
Object = 0x0a,
Function = 0x0b,
// Instance = 0x0c,
Pointer = 0x0d,
Register = 0x0e,
// External = 0x0f,
Builtin = 0x10,
Class = 0x11,
}
#[derive(Hash, PartialEq, Eq, Clone)]
enum LocationRef {
DefinitionRef(DefinitionRef),
LabelRef(LabelRef),
}
impl std::fmt::Display for LocationRef {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LocationRef::DefinitionRef(def) => write!(f, "{}", def),
LocationRef::LabelRef(label) => write!(f, "{}", label),
}
}
}
#[derive(Default)]
struct LocationMap {
references: HashMap<LocationRef, Vec<usize>>,
found_locations: HashMap<LocationRef, usize>,
}
impl LocationMap {
fn add_unresolved(&mut self, ref_: LocationRef, output: &mut Vec<u8>) {
self.references.entry(ref_).or_default().push(output.len());
output.push(0xff);
output.push(0xff); // TODO: Support >65535
}
fn resolve(&self, output: &mut Vec<u8>) {
for (name, ref_locations) in &self.references {
let location_optional = self.found_locations.get(name);
if location_optional.is_none() {
std::panic!("Unresolved reference to {} at {}", name, ref_locations[0]);
}
let location = location_optional.unwrap();
for ref_location in ref_locations {
output[*ref_location] = (*location % 256) as u8;
output[*ref_location + 1] = (*location / 256) as u8; // TODO: Support >65535
}
}
}
}
#[derive(Default)]
struct AssemblerFnData {
register_map: HashMap<Register, u8>,
register_count_pos: usize,
labels_map: LocationMap,
}

View File

@@ -1,7 +1,5 @@
// pub fn foo() -> Assembly {}
struct Assembly {
definitions: Vec<Definition>,
pub struct Assembly {
pub definitions: Vec<Definition>,
}
impl std::fmt::Display for Assembly {
@@ -14,9 +12,9 @@ impl std::fmt::Display for Assembly {
}
}
struct Definition {
ref_: DefinitionRef,
content: DefinitionContent,
pub struct Definition {
pub ref_: DefinitionRef,
pub content: DefinitionContent,
}
impl std::fmt::Display for Definition {
@@ -25,8 +23,9 @@ impl std::fmt::Display for Definition {
}
}
enum DefinitionContent {
pub enum DefinitionContent {
Function(Function),
Class(Class),
Value(Value),
}
@@ -36,6 +35,9 @@ impl std::fmt::Display for DefinitionContent {
DefinitionContent::Function(function) => {
write!(f, "{}", function)
}
DefinitionContent::Class(class) => {
write!(f, "{}", class)
}
DefinitionContent::Value(value) => {
write!(f, "{}", value)
}
@@ -43,8 +45,9 @@ impl std::fmt::Display for DefinitionContent {
}
}
struct DefinitionRef {
name: String,
#[derive(Hash, PartialEq, Eq, Clone)]
pub struct DefinitionRef {
pub name: String,
}
impl std::fmt::Display for DefinitionRef {
@@ -53,9 +56,9 @@ impl std::fmt::Display for DefinitionRef {
}
}
struct Function {
parameters: Vec<Register>,
body: Vec<InstructionOrLabel>,
pub struct Function {
pub parameters: Vec<Register>,
pub body: Vec<InstructionOrLabel>,
}
impl std::fmt::Display for Function {
@@ -82,10 +85,38 @@ impl std::fmt::Display for Function {
}
}
enum Register {
pub struct Class {
pub constructor: Value,
pub methods: Value,
}
impl std::fmt::Display for Class {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "class({}, ", self.constructor)?;
match &self.methods {
Value::Object(object) => {
write!(f, "{{\n")?;
for (name, method) in &object.properties {
write!(f, " {}: {}\n", name, method)?;
}
write!(f, "}})\n")?;
}
_ => {
write!(f, "{})\n", self.methods)?;
}
}
return Ok(());
}
}
#[derive(Hash, PartialEq, Eq, Clone)]
pub enum Register {
Return,
This,
Named(String),
Ignore,
}
impl std::fmt::Display for Register {
@@ -94,11 +125,12 @@ impl std::fmt::Display for Register {
Register::Return => write!(f, "%return"),
Register::This => write!(f, "%this"),
Register::Named(name) => write!(f, "%{}", name),
Register::Ignore => write!(f, "%ignore"),
}
}
}
enum InstructionOrLabel {
pub enum InstructionOrLabel {
Instruction(Instruction),
Label(Label),
}
@@ -116,8 +148,16 @@ impl std::fmt::Display for InstructionOrLabel {
}
}
struct Label {
name: String,
pub struct Label {
pub name: String,
}
impl Label {
pub fn ref_(&self) -> LabelRef {
LabelRef {
name: self.name.clone(),
}
}
}
impl std::fmt::Display for Label {
@@ -126,8 +166,9 @@ impl std::fmt::Display for Label {
}
}
struct LabelRef {
name: String,
#[derive(Hash, PartialEq, Eq, Clone)]
pub struct LabelRef {
pub name: String,
}
impl std::fmt::Display for LabelRef {
@@ -176,8 +217,8 @@ pub enum Instruction {
Sub(Value, Value, Register),
SubMov(Value, Value, Register),
SubCall(Value, Value, Value, Register),
Jmp(Label),
JmpIf(Value, Label),
Jmp(LabelRef),
JmpIf(Value, LabelRef),
UnaryPlus(Value, Register),
UnaryMinus(Value, Register),
New(Value, Value, Register),
@@ -297,9 +338,9 @@ impl std::fmt::Display for Instruction {
Instruction::SubCall(obj, subscript, args, register) => {
write!(f, "subcall {} {} {} {}", obj, subscript, args, register)
}
Instruction::Jmp(label) => write!(f, "jmp {}", label),
Instruction::JmpIf(value, label) => {
write!(f, "jmpif {} {}", value, label)
Instruction::Jmp(label_ref) => write!(f, "jmp {}", label_ref),
Instruction::JmpIf(value, label_ref) => {
write!(f, "jmpif {} {}", value, label_ref)
}
Instruction::UnaryPlus(value, register) => {
write!(f, "unary+ {} {}", value, register)
@@ -314,7 +355,61 @@ impl std::fmt::Display for Instruction {
}
}
enum Value {
impl Instruction {
pub fn byte(&self) -> u8 {
use Instruction::*;
// TODO: Define this in one place only
match self {
End => 0x00,
Mov(..) => 0x01,
OpInc(..) => 0x02,
OpDec(..) => 0x03,
OpPlus(..) => 0x04,
OpMinus(..) => 0x05,
OpMul(..) => 0x06,
OpDiv(..) => 0x07,
OpMod(..) => 0x08,
OpExp(..) => 0x09,
OpEq(..) => 0x0a,
OpNe(..) => 0x0b,
OpTripleEq(..) => 0x0c,
OpTripleNe(..) => 0x0d,
OpAnd(..) => 0x0e,
OpOr(..) => 0x0f,
OpNot(..) => 0x10,
OpLess(..) => 0x11,
OpLessEq(..) => 0x12,
OpGreater(..) => 0x13,
OpGreaterEq(..) => 0x14,
OpNullishCoalesce(..) => 0x15,
OpOptionalChain(..) => 0x16,
OpBitAnd(..) => 0x17,
OpBitOr(..) => 0x18,
OpBitNot(..) => 0x19,
OpBitXor(..) => 0x1a,
OpLeftShift(..) => 0x1b,
OpRightShift(..) => 0x1c,
OpRightShiftUnsigned(..) => 0x1d,
TypeOf(..) => 0x1e,
InstanceOf(..) => 0x1f,
In(..) => 0x20,
Call(..) => 0x21,
Apply(..) => 0x22,
Bind(..) => 0x23,
Sub(..) => 0x24,
SubMov(..) => 0x25,
SubCall(..) => 0x26,
Jmp(..) => 0x27,
JmpIf(..) => 0x28,
UnaryPlus(..) => 0x29,
UnaryMinus(..) => 0x2a,
New(..) => 0x2b,
}
}
}
pub enum Value {
Undefined,
Null,
Boolean(bool),
@@ -324,7 +419,6 @@ enum Value {
Object(Box<Object>),
Register(Register),
DefinitionRef(DefinitionRef),
LabelRef(LabelRef),
}
impl std::fmt::Display for Value {
@@ -343,13 +437,12 @@ impl std::fmt::Display for Value {
Value::Object(value) => write!(f, "{}", value),
Value::Register(value) => write!(f, "{}", value),
Value::DefinitionRef(value) => write!(f, "{}", value),
Value::LabelRef(value) => write!(f, "{}", value),
}
}
}
struct Array {
values: Vec<Value>,
pub struct Array {
pub values: Vec<Value>,
}
impl std::fmt::Display for Array {
@@ -365,8 +458,8 @@ impl std::fmt::Display for Array {
}
}
struct Object {
properties: Vec<(String, Value)>,
pub struct Object {
pub properties: Vec<(Value, Value)>,
}
impl std::fmt::Display for Object {
@@ -380,12 +473,7 @@ impl std::fmt::Display for Object {
if i > 0 {
write!(f, ", ")?;
}
write!(
f,
"{}: {}",
serde_json::to_string(&key).expect("Failed json serialization"),
value
)?;
write!(f, "{}: {}", key, value)?;
}
write!(f, " }}")
}

View File

@@ -1,4 +1,5 @@
mod assemble;
mod assembler;
mod assembly_ast;
mod capture_finder;
mod compile;