mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
362 lines
9.1 KiB
Rust
362 lines
9.1 KiB
Rust
// Copyright 2019 Jeremy Wall
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
use std::rc::Rc;
|
|
|
|
mod cache;
|
|
mod debug;
|
|
mod display;
|
|
pub mod environment;
|
|
#[macro_use]
|
|
pub mod error;
|
|
mod convert;
|
|
pub mod pointer;
|
|
mod runtime;
|
|
pub mod scope;
|
|
pub mod translate;
|
|
mod vm;
|
|
|
|
pub use environment::Environment;
|
|
pub use error::Error;
|
|
pub use vm::VM;
|
|
|
|
use crate::ast::{CastType, Position};
|
|
use pointer::OpPointer;
|
|
use scope::Stack;
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum Primitive {
|
|
// Primitive Types
|
|
Int(i64),
|
|
Float(f64),
|
|
Str(String),
|
|
Bool(bool),
|
|
Empty,
|
|
}
|
|
|
|
use Primitive::{Bool, Empty, Float, Int, Str};
|
|
|
|
impl Value {
|
|
fn type_name(&self) -> &'static str {
|
|
match self {
|
|
P(Int(_)) => "Int",
|
|
P(Float(_)) => "Float",
|
|
P(Str(_)) => "String",
|
|
P(Bool(_)) => "Bool",
|
|
P(Empty) => "NULL",
|
|
C(List(_, _)) => "List",
|
|
C(Tuple(_, _)) => "Tuple",
|
|
F(_) => "Func",
|
|
M(_) => "Func",
|
|
T(_) => "Expression",
|
|
S(_) => "Symbol",
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum Composite {
|
|
List(Vec<Rc<Value>>, Vec<Position>),
|
|
Tuple(Vec<(String, Rc<Value>)>, Vec<(Position, Position)>),
|
|
}
|
|
|
|
use Composite::{List, Tuple};
|
|
|
|
impl From<&Composite> for String {
|
|
fn from(c: &Composite) -> Self {
|
|
let mut buf = String::new();
|
|
match c {
|
|
&List(ref elems, _) => {
|
|
buf.push_str("[");
|
|
for e in elems.iter() {
|
|
let val: String = e.as_ref().into();
|
|
buf.push_str(&val);
|
|
buf.push_str(",");
|
|
}
|
|
buf.push_str("]");
|
|
}
|
|
&Tuple(ref flds, _) => {
|
|
buf.push_str("{");
|
|
for &(ref k, ref v) in flds.iter() {
|
|
buf.push_str(&k);
|
|
buf.push_str(" = ");
|
|
let val: String = v.as_ref().into();
|
|
buf.push_str(&val);
|
|
buf.push_str(",");
|
|
}
|
|
buf.push_str("}");
|
|
}
|
|
}
|
|
buf
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub struct Func {
|
|
ptr: OpPointer,
|
|
bindings: Vec<String>,
|
|
snapshot: Stack,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub struct Module {
|
|
ptr: OpPointer,
|
|
result_ptr: Option<usize>,
|
|
flds: Vec<(String, Rc<Value>)>,
|
|
flds_pos_list: Vec<(Position, Position)>,
|
|
pkg_ptr: Option<OpPointer>,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub enum Value {
|
|
// Binding names.
|
|
S(String),
|
|
// Primitive Types
|
|
P(Primitive),
|
|
// Composite Types.
|
|
C(Composite),
|
|
// Program Pointer
|
|
T(usize),
|
|
// Function
|
|
F(Func),
|
|
// Module
|
|
M(Module),
|
|
}
|
|
|
|
impl From<&Value> for String {
|
|
fn from(v: &Value) -> Self {
|
|
match v {
|
|
&S(ref s) => s.clone(),
|
|
&P(ref p) => p.into(),
|
|
&C(ref c) => c.into(),
|
|
&T(_) => "<Thunk>".to_owned(),
|
|
&F(_) => "<Func>".to_owned(),
|
|
&M(_) => "<Module>".to_owned(),
|
|
}
|
|
}
|
|
}
|
|
|
|
use Value::{C, F, M, P, S, T};
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum Hook {
|
|
Map,
|
|
Include,
|
|
Filter,
|
|
Reduce,
|
|
Import,
|
|
Out,
|
|
Assert,
|
|
Convert,
|
|
Regex,
|
|
Range,
|
|
Trace(Position),
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub enum Op {
|
|
// Stack and Name manipulation.
|
|
Bind, // Bind a Val to a name in the heap
|
|
BindOver, // Overwrite a value in the heap
|
|
Pop, // Pop a Value off the value stack and discard it.
|
|
NewScope(i32),
|
|
// Math ops
|
|
Add,
|
|
Sub,
|
|
Div,
|
|
Mul,
|
|
Mod,
|
|
// Comparison Ops
|
|
Equal,
|
|
Gt,
|
|
Lt,
|
|
GtEq,
|
|
LtEq,
|
|
// Not,
|
|
Not,
|
|
// Primitive Types ops
|
|
Val(Primitive),
|
|
// Primitive casts
|
|
Cast(CastType),
|
|
// A bareword for use in bindings or lookups
|
|
Sym(String),
|
|
// Reference a binding on the heap
|
|
DeRef(String),
|
|
// Complex Type ops
|
|
InitTuple,
|
|
Field,
|
|
InitList,
|
|
Element,
|
|
// Copy Operation
|
|
Cp,
|
|
// Control Flow
|
|
Bang,
|
|
Jump(i32),
|
|
JumpIfTrue(i32),
|
|
JumpIfFalse(i32),
|
|
SelectJump(i32),
|
|
And(i32),
|
|
Or(i32),
|
|
// Spacer operation, Does nothing.
|
|
Index, // indexing operation
|
|
SafeIndex, // Safe indexing operation. Does Null Coelescing
|
|
Exist,
|
|
Noop,
|
|
// Pending Computation
|
|
InitThunk(i32), // Basically just used for module return expressions
|
|
Module(i32),
|
|
Func(i32),
|
|
Return,
|
|
// Calls
|
|
FCall,
|
|
// TypeSystem
|
|
Typ,
|
|
// Runtime hooks
|
|
Runtime(Hook),
|
|
Render,
|
|
// The self lookup for tuples.
|
|
PushSelf,
|
|
PopSelf,
|
|
}
|
|
|
|
use super::ir::Val;
|
|
|
|
impl PartialEq for Value {
|
|
fn eq(&self, other: &Value) -> bool {
|
|
match (self, other) {
|
|
(P(left), P(right)) => left == right,
|
|
(C(List(left, _)), C(List(right, _))) => left == right,
|
|
(C(Tuple(left, _)), C(Tuple(right, _))) => {
|
|
if left.len() != right.len() {
|
|
return false;
|
|
}
|
|
for (ref lk, ref lv) in left.iter() {
|
|
let mut found = false;
|
|
for (ref rk, ref rv) in right.iter() {
|
|
if lk == rk {
|
|
found = true;
|
|
if lv != rv {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
if !found {
|
|
return false;
|
|
}
|
|
}
|
|
true
|
|
}
|
|
(F(left), F(right)) => left == right,
|
|
(M(left), M(right)) => left == right,
|
|
(T(_), T(_)) | (S(_), S(_)) => false,
|
|
(_, _) => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO(jwall): Move all of this into the convert module.
|
|
impl From<Rc<Value>> for Val {
|
|
fn from(val: Rc<Value>) -> Val {
|
|
val.as_ref().into()
|
|
}
|
|
}
|
|
|
|
impl From<Value> for Val {
|
|
fn from(val: Value) -> Val {
|
|
(&val).into()
|
|
}
|
|
}
|
|
|
|
impl From<&Value> for Val {
|
|
fn from(val: &Value) -> Val {
|
|
match val {
|
|
P(Int(i)) => Val::Int(*i),
|
|
P(Float(f)) => Val::Float(*f),
|
|
P(Str(s)) => Val::Str(s.clone()),
|
|
P(Bool(b)) => Val::Boolean(*b),
|
|
C(Tuple(fs, _)) => {
|
|
let mut flds = Vec::new();
|
|
for &(ref k, ref v) in fs.iter() {
|
|
let v = v.clone();
|
|
flds.push((k.clone(), Rc::new(v.into())));
|
|
}
|
|
Val::Tuple(flds)
|
|
}
|
|
C(List(elems, _)) => {
|
|
let mut els = Vec::new();
|
|
for e in elems.iter() {
|
|
let e = e.clone();
|
|
els.push(Rc::new(e.into()));
|
|
}
|
|
Val::List(els)
|
|
}
|
|
S(_) | F(_) | M(_) | T(_) | P(Empty) => Val::Empty,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Rc<Val>> for Value {
|
|
fn from(val: Rc<Val>) -> Self {
|
|
val.as_ref().into()
|
|
}
|
|
}
|
|
|
|
impl From<Val> for Value {
|
|
fn from(val: Val) -> Self {
|
|
(&val).into()
|
|
}
|
|
}
|
|
|
|
impl From<&Val> for Value {
|
|
fn from(val: &Val) -> Self {
|
|
match val {
|
|
Val::Int(i) => P(Int(*i)),
|
|
Val::Float(f) => P(Float(*f)),
|
|
Val::Boolean(b) => P(Bool(*b)),
|
|
Val::Str(s) => P(Str(s.clone())),
|
|
Val::Empty => P(Empty),
|
|
Val::List(els) => {
|
|
let mut lst = Vec::new();
|
|
let mut positions = Vec::new();
|
|
for e in els.iter() {
|
|
let e = e.clone();
|
|
lst.push(Rc::new(e.into()));
|
|
positions.push(Position::new(0, 0, 0));
|
|
}
|
|
// TODO(jwall): This should have a set of
|
|
// Positions of the same length.
|
|
C(List(lst, positions))
|
|
}
|
|
Val::Tuple(flds) => {
|
|
let mut field_list = Vec::new();
|
|
let mut positions = Vec::new();
|
|
for &(ref key, ref val) in flds.iter() {
|
|
let val = val.clone();
|
|
field_list.push((key.clone(), Rc::new(val.into())));
|
|
positions.push((Position::new(0, 0, 0), Position::new(0, 0, 0)));
|
|
}
|
|
C(Tuple(field_list, positions))
|
|
}
|
|
Val::Env(flds) => {
|
|
let mut field_list = Vec::new();
|
|
let mut positions = Vec::new();
|
|
for &(ref key, ref val) in flds.iter() {
|
|
field_list.push((key.clone(), Rc::new(P(Str(val.clone())))));
|
|
positions.push((Position::new(0, 0, 0), Position::new(0, 0, 0)));
|
|
}
|
|
C(Tuple(field_list, positions))
|
|
}
|
|
}
|
|
}
|
|
}
|