2024-09-30 15:15:41 -07:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::fmt::{self, Debug, Display};
|
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
|
|
|
|
use gc::{Finalize, Trace};
|
|
|
|
|
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
use crate::obj::{macros::*, prelude::*, Obj, BUILTINS};
|
2024-09-30 15:15:41 -07:00
|
|
|
use crate::vm::{Argc, Vm};
|
|
|
|
|
|
|
|
|
|
#[derive(Trace, Finalize)]
|
|
|
|
|
pub struct Ty {
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
base: Obj,
|
2024-09-30 15:15:41 -07:00
|
|
|
#[unsafe_ignore_trace]
|
|
|
|
|
name: Rc<String>,
|
|
|
|
|
vtable: HashMap<String, ObjP>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Ty {
|
|
|
|
|
pub fn new(name: impl ToString) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
name: Rc::new(name.to_string()),
|
|
|
|
|
base: Default::default(),
|
|
|
|
|
vtable: Default::default(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn name(&self) -> &Rc<String> {
|
|
|
|
|
&self.name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn vtable(&self) -> &HashMap<String, ObjP> {
|
|
|
|
|
&self.vtable
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_create!(name: impl ToString);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Debug for Ty {
|
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
write!(
|
|
|
|
|
fmt,
|
|
|
|
|
"<Ty {} at {:#x}>",
|
|
|
|
|
self.name,
|
|
|
|
|
(self as *const _ as usize)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Display for Ty {
|
|
|
|
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
|
Debug::fmt(self, fmt)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Object for Ty {
|
|
|
|
|
fn call(&self, vm: &mut Vm, argc: Argc) {
|
|
|
|
|
// TODO Object::call - need to handle "this object cannot be called" errors
|
|
|
|
|
// BLOCKED-ON: exceptions
|
|
|
|
|
|
|
|
|
|
// I don't think there's any way we could call this *without* it being a method.
|
|
|
|
|
// If you do e.g. `Int.__call__`, Int is an object, so it should be doing `__call__` as a
|
|
|
|
|
// vtable value.
|
|
|
|
|
|
2024-10-07 15:24:06 -07:00
|
|
|
let index = vm.stack().len() - 1 - argc as usize;
|
|
|
|
|
let this = vm.stack()[index].clone();
|
|
|
|
|
|
|
|
|
|
assert!(
|
|
|
|
|
std::ptr::addr_eq(&*this.borrow(), self),
|
|
|
|
|
"calling {}.__call__ on type that is not ourselves",
|
|
|
|
|
self.ty_name()
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Additionally, we want to duplicate the type argument on the stack.
|
|
|
|
|
//
|
|
|
|
|
// When you call a new constructor, e.g. `MyType(arg1, arg2, arg3)`, the stack will look like this:
|
|
|
|
|
//
|
|
|
|
|
// -- stack top
|
|
|
|
|
// arg3
|
|
|
|
|
// arg2
|
|
|
|
|
// arg1
|
|
|
|
|
// <Ty MyType> <---- NOTE - this is what we are actually calling, and is being treated as a function
|
|
|
|
|
// ...
|
|
|
|
|
// -- stack bottom
|
|
|
|
|
//
|
|
|
|
|
// With a custom type, we want to be getting the __init__ function off of the type. Since
|
|
|
|
|
// we don't have access to the function in the call stack (in this case, it's our type),
|
|
|
|
|
// we duplicate the type to be the first argument.
|
|
|
|
|
vm.stack_mut().insert(index, this);
|
2024-09-30 15:15:41 -07:00
|
|
|
|
|
|
|
|
let function = self
|
|
|
|
|
.vtable
|
|
|
|
|
.get("__call__")
|
|
|
|
|
.expect("Why does a type not have a __call__ member?");
|
2024-10-07 15:24:06 -07:00
|
|
|
function.borrow().call(vm, argc + 1);
|
2024-09-30 15:15:41 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn arity(&self) -> Option<Argc> {
|
|
|
|
|
// HACK XXX NOTE Ty __call__ arity :
|
|
|
|
|
// We need to tread carefully here. Normally, `__call__` would be wrapped as a method.
|
|
|
|
|
// However, we have to get the `__call__` member directly from the vtable.
|
|
|
|
|
// We are subtracting 1 from the arity, because whenever it *does* become a method, the
|
|
|
|
|
// arity will match when we call `Ty` directly.
|
|
|
|
|
self.vtable
|
|
|
|
|
.get("__call__")
|
|
|
|
|
.and_then(|function| function.borrow().arity())
|
|
|
|
|
.map(|n| n - 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl_base_obj!(Ty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn init_types() {
|
|
|
|
|
#![allow(non_snake_case)]
|
|
|
|
|
macro_rules! types {
|
|
|
|
|
(
|
|
|
|
|
base_type: $base_type:ident,
|
|
|
|
|
$(
|
|
|
|
|
$name:ident {
|
|
|
|
|
$( $vtable_name:ident => $vtable_value:expr ),* $(,)?
|
|
|
|
|
}
|
|
|
|
|
),* $(,)?
|
|
|
|
|
) => {{
|
|
|
|
|
$(
|
|
|
|
|
let $name = make_ptr(Ty::new(stringify!($name)));
|
|
|
|
|
BUILTINS.with_borrow_mut(|builtins| builtins.insert(stringify!($name).to_string(), $name.clone()));
|
|
|
|
|
)*
|
|
|
|
|
|
|
|
|
|
// We have to instantiate these objects all by hand. This is because the `instantiate`
|
|
|
|
|
// function does some stuff that may accidentally cause infinite recursion while we are
|
|
|
|
|
// setting up these fundamental types.
|
|
|
|
|
$({
|
|
|
|
|
let base_type = $base_type.clone();
|
|
|
|
|
$name.borrow_mut().set_attr("__ty__", base_type);
|
|
|
|
|
with_obj_downcast_mut($name.clone(), |ty: &mut Ty| { ty.base.is_instantiated = true; });
|
|
|
|
|
})*
|
|
|
|
|
|
|
|
|
|
$({
|
|
|
|
|
$(
|
|
|
|
|
let vtable_name = stringify!($vtable_name);
|
|
|
|
|
let vtable_value = $vtable_value;
|
|
|
|
|
with_obj_downcast_mut($name.clone(), |ty: &mut Ty| {
|
|
|
|
|
ty.vtable.insert(vtable_name.to_string(), vtable_value);
|
|
|
|
|
});
|
|
|
|
|
)*
|
|
|
|
|
})*
|
|
|
|
|
}};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
types! {
|
|
|
|
|
// base type
|
|
|
|
|
base_type: Ty,
|
|
|
|
|
// type definitions
|
|
|
|
|
Ty {
|
|
|
|
|
// Constructor
|
|
|
|
|
// TODO Ty::do_call, Ty::init - implement these methods
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
__call__ => BuiltinFunction::create("__call__", Obj::not_implemented_un, 1),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Obj::not_implemented_un, 1),
|
|
|
|
|
|
|
|
|
|
// Conversion methods
|
|
|
|
|
to_str => BuiltinFunction::create("to_str", Obj::to_str, 1),
|
|
|
|
|
to_repr => BuiltinFunction::create("to_repr", Obj::to_repr, 1),
|
|
|
|
|
to_bool => BuiltinFunction::create("to_bool", Obj::to_bool, 1),
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", Obj::not_implemented_un, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", Obj::not_implemented_un, 1),
|
|
|
|
|
to_list => BuiltinFunction::create("to_list", Obj::not_implemented_un, 1),
|
2024-09-30 15:15:41 -07:00
|
|
|
|
|
|
|
|
// Operators
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
__add__ => BuiltinFunction::create("__add__", Obj::not_implemented_bin, 2),
|
|
|
|
|
__sub__ => BuiltinFunction::create("__sub__", Obj::not_implemented_bin, 2),
|
|
|
|
|
__mul__ => BuiltinFunction::create("__mul__", Obj::not_implemented_bin, 2),
|
|
|
|
|
__div__ => BuiltinFunction::create("__div__", Obj::not_implemented_bin, 2),
|
|
|
|
|
__and__ => BuiltinFunction::create("__and__", Obj::and, 2),
|
|
|
|
|
__or__ => BuiltinFunction::create("__or__", Obj::or, 2),
|
|
|
|
|
__ne__ => BuiltinFunction::create("__ne__", Obj::ne, 2),
|
|
|
|
|
__eq__ => BuiltinFunction::create("__eq__", Obj::eq, 2),
|
|
|
|
|
__gt__ => BuiltinFunction::create("__gt__", Obj::not_implemented_bin, 2),
|
|
|
|
|
__ge__ => BuiltinFunction::create("__ge__", Obj::not_implemented_bin, 2),
|
|
|
|
|
__lt__ => BuiltinFunction::create("__lt__", Obj::not_implemented_bin, 2),
|
|
|
|
|
__le__ => BuiltinFunction::create("__le__", Obj::not_implemented_bin, 2),
|
|
|
|
|
__pos__ => BuiltinFunction::create("__pos__", Obj::not_implemented_un, 1),
|
|
|
|
|
__neg__ => BuiltinFunction::create("__neg__", Obj::not_implemented_un, 1),
|
|
|
|
|
__not__ => BuiltinFunction::create("__not__", Obj::not, 1),
|
2024-09-30 17:46:03 -07:00
|
|
|
|
|
|
|
|
// Methods
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
len => BuiltinFunction::create("len", Obj::not_implemented_un, 1),
|
|
|
|
|
hash => BuiltinFunction::create("hash", Obj::not_implemented_bin, 2),
|
2024-09-30 15:15:41 -07:00
|
|
|
},
|
|
|
|
|
Obj {
|
2024-10-07 15:24:06 -07:00
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Obj::do_call, 1),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Obj::init, 1),
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
|
WIP: Add imports and modules
This is a big change because it touches a lot of stuff, but here is the
overview:
* Import syntax:
```
import foo
import bar from foo
import bar from "foo.npp"
import bar, baz from foo
import * from foo
import "foo.npp"
```
* These are all valid imports. They should be pretty
straightforward, maybe with exception of the last item. If you are
importing a path directly, but not importing any members from it,
it does not insert anything into the current namespace, and just
executes the file. This is probably going to be unused but I want
to include it for completeness. We can always remove it later
before a hypothetical 1.0 release.
* The "from" keyword is only ever used as a keyword here, and I am
allowing it to be used as an identifier elsewhere. Don't export
it, because that's weird and wrong and won't work.
* Modules:
* Doing an `import foo` will look for "foo.npp" at compile-time,
relative to the importer's directory, parse it, and compile it.
The importer will then attempt to execute the module with the new
`EnterModule` op. This instruction will execute the module kind of
like a function, assigning the module's global namespace to an
object that you can pass around.
* `import bar from foo` and `import bar from "foo.npp"` et al syntax
is not currently implemented in the compiler.
* There is a new "Module" object that represents a potentially
un-initialized module. This can't be referred to directly in code.
* VM:
* The VM operates around Module objects now. If you want to "call" a
new module, you should call `enter_module`. This is how the main
chunk is invoked.
* TODOs:
* `exit_module` function in the VM
* Finish up module implementation in compiler
* Built-in modules
* Sub-modules - e.g. `import foo.bar` - how does naming work for
this?
* Module directories. In Python you have `foo/__init__.py` and in
Rust you have `foo/mod.rs`.
* Probably a "Namespace" object that explicitly denotes "this is an
imported module that you're dealing with"
* Tests, tests, tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-04 10:11:49 -07:00
|
|
|
// Methods
|
2024-09-30 15:15:41 -07:00
|
|
|
},
|
2024-09-30 16:33:58 -07:00
|
|
|
List {
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", List::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", List::init, 2),
|
|
|
|
|
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Conversion methods
|
|
|
|
|
to_repr => BuiltinFunction::create("to_repr", List::to_repr, 1),
|
|
|
|
|
to_list => BuiltinFunction::create("to_list", List::to_list, 1),
|
|
|
|
|
|
2024-09-30 16:33:58 -07:00
|
|
|
// Operators
|
|
|
|
|
__index__ => BuiltinFunction::create("__index__", List::index, 2),
|
|
|
|
|
|
|
|
|
|
// Methods
|
2024-09-30 17:46:03 -07:00
|
|
|
len => BuiltinFunction::create("len", List::len, 1),
|
|
|
|
|
|
2024-09-30 16:33:58 -07:00
|
|
|
push => BuiltinFunction::create("push", List::push, 2),
|
|
|
|
|
pop => BuiltinFunction::create("pop", List::pop, 1),
|
2024-09-30 19:53:31 -07:00
|
|
|
extend => BuiltinFunction::create("extend", List::extend, 2),
|
2024-09-30 16:33:58 -07:00
|
|
|
},
|
2024-09-30 15:15:41 -07:00
|
|
|
Str {
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Str::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Str::init, 2),
|
|
|
|
|
|
2024-09-30 15:15:41 -07:00
|
|
|
// Conversion methods
|
|
|
|
|
to_str => BuiltinFunction::create("to_str", Str::to_str, 1),
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", Str::to_int, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", Str::to_float, 1),
|
2024-09-30 16:49:48 -07:00
|
|
|
to_list => BuiltinFunction::create("to_list", Str::to_list, 1),
|
2024-09-30 15:15:41 -07:00
|
|
|
|
|
|
|
|
// Operators
|
|
|
|
|
__add__ => BuiltinFunction::create("__add__", Str::add, 2),
|
|
|
|
|
__mul__ => BuiltinFunction::create("__mul__", Str::mul, 2),
|
2024-09-30 16:33:58 -07:00
|
|
|
|
2024-09-30 16:49:48 -07:00
|
|
|
__index__ => BuiltinFunction::create("__index__", Str::index, 2),
|
|
|
|
|
|
2024-09-30 16:33:58 -07:00
|
|
|
// Methods
|
2024-09-30 17:46:03 -07:00
|
|
|
len => BuiltinFunction::create("len", Str::len, 1),
|
2024-09-30 16:33:58 -07:00
|
|
|
// TODO Str methods - .lower, .upper, .slice, etc
|
2024-09-30 15:15:41 -07:00
|
|
|
},
|
|
|
|
|
Int {
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Int::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Int::init, 2),
|
|
|
|
|
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Conversion methods
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", Int::to_int, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", Int::to_float, 1),
|
|
|
|
|
|
2024-09-30 15:15:41 -07:00
|
|
|
// Operators
|
|
|
|
|
__add__ => BuiltinFunction::create("__add__", Int::add, 2),
|
|
|
|
|
__sub__ => BuiltinFunction::create("__sub__", Int::sub, 2),
|
|
|
|
|
__mul__ => BuiltinFunction::create("__mul__", Int::mul, 2),
|
|
|
|
|
__div__ => BuiltinFunction::create("__div__", Int::div, 2),
|
|
|
|
|
//__eq__ => BuiltinFunction::create("__eq__", Int::eq, 2),
|
|
|
|
|
__gt__ => BuiltinFunction::create("__gt__", Int::gt, 2),
|
|
|
|
|
__ge__ => BuiltinFunction::create("__ge__", Int::ge, 2),
|
|
|
|
|
__lt__ => BuiltinFunction::create("__lt__", Int::lt, 2),
|
|
|
|
|
__le__ => BuiltinFunction::create("__le__", Int::le, 2),
|
|
|
|
|
__pos__ => BuiltinFunction::create("__pos__", Int::pos, 1),
|
|
|
|
|
__neg__ => BuiltinFunction::create("__neg__", Int::neg, 1),
|
WIP: Add imports and modules
This is a big change because it touches a lot of stuff, but here is the
overview:
* Import syntax:
```
import foo
import bar from foo
import bar from "foo.npp"
import bar, baz from foo
import * from foo
import "foo.npp"
```
* These are all valid imports. They should be pretty
straightforward, maybe with exception of the last item. If you are
importing a path directly, but not importing any members from it,
it does not insert anything into the current namespace, and just
executes the file. This is probably going to be unused but I want
to include it for completeness. We can always remove it later
before a hypothetical 1.0 release.
* The "from" keyword is only ever used as a keyword here, and I am
allowing it to be used as an identifier elsewhere. Don't export
it, because that's weird and wrong and won't work.
* Modules:
* Doing an `import foo` will look for "foo.npp" at compile-time,
relative to the importer's directory, parse it, and compile it.
The importer will then attempt to execute the module with the new
`EnterModule` op. This instruction will execute the module kind of
like a function, assigning the module's global namespace to an
object that you can pass around.
* `import bar from foo` and `import bar from "foo.npp"` et al syntax
is not currently implemented in the compiler.
* There is a new "Module" object that represents a potentially
un-initialized module. This can't be referred to directly in code.
* VM:
* The VM operates around Module objects now. If you want to "call" a
new module, you should call `enter_module`. This is how the main
chunk is invoked.
* TODOs:
* `exit_module` function in the VM
* Finish up module implementation in compiler
* Built-in modules
* Sub-modules - e.g. `import foo.bar` - how does naming work for
this?
* Module directories. In Python you have `foo/__init__.py` and in
Rust you have `foo/mod.rs`.
* Probably a "Namespace" object that explicitly denotes "this is an
imported module that you're dealing with"
* Tests, tests, tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-04 10:11:49 -07:00
|
|
|
// Methods
|
2024-09-30 15:15:41 -07:00
|
|
|
},
|
|
|
|
|
Float {
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Float::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Float::init, 2),
|
|
|
|
|
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Conversion methods
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", Float::to_int, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", Float::to_float, 1),
|
|
|
|
|
|
2024-09-30 15:15:41 -07:00
|
|
|
// Operators
|
|
|
|
|
__add__ => BuiltinFunction::create("__add__", Float::add, 2),
|
|
|
|
|
__sub__ => BuiltinFunction::create("__sub__", Float::sub, 2),
|
|
|
|
|
__mul__ => BuiltinFunction::create("__mul__", Float::mul, 2),
|
|
|
|
|
__div__ => BuiltinFunction::create("__div__", Float::div, 2),
|
|
|
|
|
__gt__ => BuiltinFunction::create("__gt__", Float::gt, 2),
|
|
|
|
|
__ge__ => BuiltinFunction::create("__ge__", Float::ge, 2),
|
|
|
|
|
__lt__ => BuiltinFunction::create("__lt__", Float::lt, 2),
|
|
|
|
|
__le__ => BuiltinFunction::create("__le__", Float::le, 2),
|
|
|
|
|
__pos__ => BuiltinFunction::create("__pos__", Float::pos, 1),
|
|
|
|
|
__neg__ => BuiltinFunction::create("__neg__", Float::neg, 1),
|
WIP: Add imports and modules
This is a big change because it touches a lot of stuff, but here is the
overview:
* Import syntax:
```
import foo
import bar from foo
import bar from "foo.npp"
import bar, baz from foo
import * from foo
import "foo.npp"
```
* These are all valid imports. They should be pretty
straightforward, maybe with exception of the last item. If you are
importing a path directly, but not importing any members from it,
it does not insert anything into the current namespace, and just
executes the file. This is probably going to be unused but I want
to include it for completeness. We can always remove it later
before a hypothetical 1.0 release.
* The "from" keyword is only ever used as a keyword here, and I am
allowing it to be used as an identifier elsewhere. Don't export
it, because that's weird and wrong and won't work.
* Modules:
* Doing an `import foo` will look for "foo.npp" at compile-time,
relative to the importer's directory, parse it, and compile it.
The importer will then attempt to execute the module with the new
`EnterModule` op. This instruction will execute the module kind of
like a function, assigning the module's global namespace to an
object that you can pass around.
* `import bar from foo` and `import bar from "foo.npp"` et al syntax
is not currently implemented in the compiler.
* There is a new "Module" object that represents a potentially
un-initialized module. This can't be referred to directly in code.
* VM:
* The VM operates around Module objects now. If you want to "call" a
new module, you should call `enter_module`. This is how the main
chunk is invoked.
* TODOs:
* `exit_module` function in the VM
* Finish up module implementation in compiler
* Built-in modules
* Sub-modules - e.g. `import foo.bar` - how does naming work for
this?
* Module directories. In Python you have `foo/__init__.py` and in
Rust you have `foo/mod.rs`.
* Probably a "Namespace" object that explicitly denotes "this is an
imported module that you're dealing with"
* Tests, tests, tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-04 10:11:49 -07:00
|
|
|
// Methods
|
2024-09-30 15:15:41 -07:00
|
|
|
},
|
|
|
|
|
Bool {
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Bool::do_call, 2),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Bool::init, 2),
|
|
|
|
|
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Conversion methods
|
|
|
|
|
to_int => BuiltinFunction::create("to_int", Bool::to_int, 1),
|
|
|
|
|
to_float => BuiltinFunction::create("to_float", Bool::to_float, 1),
|
|
|
|
|
|
2024-09-30 15:15:41 -07:00
|
|
|
// Operators
|
WIP: Add imports and modules
This is a big change because it touches a lot of stuff, but here is the
overview:
* Import syntax:
```
import foo
import bar from foo
import bar from "foo.npp"
import bar, baz from foo
import * from foo
import "foo.npp"
```
* These are all valid imports. They should be pretty
straightforward, maybe with exception of the last item. If you are
importing a path directly, but not importing any members from it,
it does not insert anything into the current namespace, and just
executes the file. This is probably going to be unused but I want
to include it for completeness. We can always remove it later
before a hypothetical 1.0 release.
* The "from" keyword is only ever used as a keyword here, and I am
allowing it to be used as an identifier elsewhere. Don't export
it, because that's weird and wrong and won't work.
* Modules:
* Doing an `import foo` will look for "foo.npp" at compile-time,
relative to the importer's directory, parse it, and compile it.
The importer will then attempt to execute the module with the new
`EnterModule` op. This instruction will execute the module kind of
like a function, assigning the module's global namespace to an
object that you can pass around.
* `import bar from foo` and `import bar from "foo.npp"` et al syntax
is not currently implemented in the compiler.
* There is a new "Module" object that represents a potentially
un-initialized module. This can't be referred to directly in code.
* VM:
* The VM operates around Module objects now. If you want to "call" a
new module, you should call `enter_module`. This is how the main
chunk is invoked.
* TODOs:
* `exit_module` function in the VM
* Finish up module implementation in compiler
* Built-in modules
* Sub-modules - e.g. `import foo.bar` - how does naming work for
this?
* Module directories. In Python you have `foo/__init__.py` and in
Rust you have `foo/mod.rs`.
* Probably a "Namespace" object that explicitly denotes "this is an
imported module that you're dealing with"
* Tests, tests, tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-04 10:11:49 -07:00
|
|
|
// Methods
|
2024-09-30 15:15:41 -07:00
|
|
|
},
|
|
|
|
|
Nil {
|
|
|
|
|
// Constructor
|
|
|
|
|
__call__ => BuiltinFunction::create("__call__", Nil::do_call, 1),
|
|
|
|
|
__init__ => BuiltinFunction::create("__init__", Nil::init, 1),
|
|
|
|
|
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Conversion methods
|
|
|
|
|
|
2024-09-30 15:15:41 -07:00
|
|
|
// Operators
|
WIP: Add imports and modules
This is a big change because it touches a lot of stuff, but here is the
overview:
* Import syntax:
```
import foo
import bar from foo
import bar from "foo.npp"
import bar, baz from foo
import * from foo
import "foo.npp"
```
* These are all valid imports. They should be pretty
straightforward, maybe with exception of the last item. If you are
importing a path directly, but not importing any members from it,
it does not insert anything into the current namespace, and just
executes the file. This is probably going to be unused but I want
to include it for completeness. We can always remove it later
before a hypothetical 1.0 release.
* The "from" keyword is only ever used as a keyword here, and I am
allowing it to be used as an identifier elsewhere. Don't export
it, because that's weird and wrong and won't work.
* Modules:
* Doing an `import foo` will look for "foo.npp" at compile-time,
relative to the importer's directory, parse it, and compile it.
The importer will then attempt to execute the module with the new
`EnterModule` op. This instruction will execute the module kind of
like a function, assigning the module's global namespace to an
object that you can pass around.
* `import bar from foo` and `import bar from "foo.npp"` et al syntax
is not currently implemented in the compiler.
* There is a new "Module" object that represents a potentially
un-initialized module. This can't be referred to directly in code.
* VM:
* The VM operates around Module objects now. If you want to "call" a
new module, you should call `enter_module`. This is how the main
chunk is invoked.
* TODOs:
* `exit_module` function in the VM
* Finish up module implementation in compiler
* Built-in modules
* Sub-modules - e.g. `import foo.bar` - how does naming work for
this?
* Module directories. In Python you have `foo/__init__.py` and in
Rust you have `foo/mod.rs`.
* Probably a "Namespace" object that explicitly denotes "this is an
imported module that you're dealing with"
* Tests, tests, tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-04 10:11:49 -07:00
|
|
|
// Methods
|
|
|
|
|
},
|
|
|
|
|
BuiltinFunction {
|
|
|
|
|
// Constructor
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Conversion methods
|
WIP: Add imports and modules
This is a big change because it touches a lot of stuff, but here is the
overview:
* Import syntax:
```
import foo
import bar from foo
import bar from "foo.npp"
import bar, baz from foo
import * from foo
import "foo.npp"
```
* These are all valid imports. They should be pretty
straightforward, maybe with exception of the last item. If you are
importing a path directly, but not importing any members from it,
it does not insert anything into the current namespace, and just
executes the file. This is probably going to be unused but I want
to include it for completeness. We can always remove it later
before a hypothetical 1.0 release.
* The "from" keyword is only ever used as a keyword here, and I am
allowing it to be used as an identifier elsewhere. Don't export
it, because that's weird and wrong and won't work.
* Modules:
* Doing an `import foo` will look for "foo.npp" at compile-time,
relative to the importer's directory, parse it, and compile it.
The importer will then attempt to execute the module with the new
`EnterModule` op. This instruction will execute the module kind of
like a function, assigning the module's global namespace to an
object that you can pass around.
* `import bar from foo` and `import bar from "foo.npp"` et al syntax
is not currently implemented in the compiler.
* There is a new "Module" object that represents a potentially
un-initialized module. This can't be referred to directly in code.
* VM:
* The VM operates around Module objects now. If you want to "call" a
new module, you should call `enter_module`. This is how the main
chunk is invoked.
* TODOs:
* `exit_module` function in the VM
* Finish up module implementation in compiler
* Built-in modules
* Sub-modules - e.g. `import foo.bar` - how does naming work for
this?
* Module directories. In Python you have `foo/__init__.py` and in
Rust you have `foo/mod.rs`.
* Probably a "Namespace" object that explicitly denotes "this is an
imported module that you're dealing with"
* Tests, tests, tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-04 10:11:49 -07:00
|
|
|
// Operators
|
|
|
|
|
// Methods
|
|
|
|
|
},
|
|
|
|
|
UserFunction {
|
|
|
|
|
// Constructor
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Conversion methods
|
WIP: Add imports and modules
This is a big change because it touches a lot of stuff, but here is the
overview:
* Import syntax:
```
import foo
import bar from foo
import bar from "foo.npp"
import bar, baz from foo
import * from foo
import "foo.npp"
```
* These are all valid imports. They should be pretty
straightforward, maybe with exception of the last item. If you are
importing a path directly, but not importing any members from it,
it does not insert anything into the current namespace, and just
executes the file. This is probably going to be unused but I want
to include it for completeness. We can always remove it later
before a hypothetical 1.0 release.
* The "from" keyword is only ever used as a keyword here, and I am
allowing it to be used as an identifier elsewhere. Don't export
it, because that's weird and wrong and won't work.
* Modules:
* Doing an `import foo` will look for "foo.npp" at compile-time,
relative to the importer's directory, parse it, and compile it.
The importer will then attempt to execute the module with the new
`EnterModule` op. This instruction will execute the module kind of
like a function, assigning the module's global namespace to an
object that you can pass around.
* `import bar from foo` and `import bar from "foo.npp"` et al syntax
is not currently implemented in the compiler.
* There is a new "Module" object that represents a potentially
un-initialized module. This can't be referred to directly in code.
* VM:
* The VM operates around Module objects now. If you want to "call" a
new module, you should call `enter_module`. This is how the main
chunk is invoked.
* TODOs:
* `exit_module` function in the VM
* Finish up module implementation in compiler
* Built-in modules
* Sub-modules - e.g. `import foo.bar` - how does naming work for
this?
* Module directories. In Python you have `foo/__init__.py` and in
Rust you have `foo/mod.rs`.
* Probably a "Namespace" object that explicitly denotes "this is an
imported module that you're dealing with"
* Tests, tests, tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-04 10:11:49 -07:00
|
|
|
// Operators
|
|
|
|
|
// Methods
|
|
|
|
|
},
|
|
|
|
|
Method {
|
|
|
|
|
// Constructor
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Conversion methods
|
WIP: Add imports and modules
This is a big change because it touches a lot of stuff, but here is the
overview:
* Import syntax:
```
import foo
import bar from foo
import bar from "foo.npp"
import bar, baz from foo
import * from foo
import "foo.npp"
```
* These are all valid imports. They should be pretty
straightforward, maybe with exception of the last item. If you are
importing a path directly, but not importing any members from it,
it does not insert anything into the current namespace, and just
executes the file. This is probably going to be unused but I want
to include it for completeness. We can always remove it later
before a hypothetical 1.0 release.
* The "from" keyword is only ever used as a keyword here, and I am
allowing it to be used as an identifier elsewhere. Don't export
it, because that's weird and wrong and won't work.
* Modules:
* Doing an `import foo` will look for "foo.npp" at compile-time,
relative to the importer's directory, parse it, and compile it.
The importer will then attempt to execute the module with the new
`EnterModule` op. This instruction will execute the module kind of
like a function, assigning the module's global namespace to an
object that you can pass around.
* `import bar from foo` and `import bar from "foo.npp"` et al syntax
is not currently implemented in the compiler.
* There is a new "Module" object that represents a potentially
un-initialized module. This can't be referred to directly in code.
* VM:
* The VM operates around Module objects now. If you want to "call" a
new module, you should call `enter_module`. This is how the main
chunk is invoked.
* TODOs:
* `exit_module` function in the VM
* Finish up module implementation in compiler
* Built-in modules
* Sub-modules - e.g. `import foo.bar` - how does naming work for
this?
* Module directories. In Python you have `foo/__init__.py` and in
Rust you have `foo/mod.rs`.
* Probably a "Namespace" object that explicitly denotes "this is an
imported module that you're dealing with"
* Tests, tests, tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-04 10:11:49 -07:00
|
|
|
// Operators
|
|
|
|
|
// Methods
|
|
|
|
|
},
|
|
|
|
|
Module {
|
|
|
|
|
// Constructor
|
Remove BaseObj and fix Object::equals
* BaseObj felt a bit redundant. For everything that BaseObj did, we use
Obj instead.
* Object::equals was a little weird. It was used for giving back
equality, except when it wasn't. It's a little better defined now,
here's what I'm shooting for:
* *In general*, Object::equals will return true when two objects
refer to the same object.
* The exception to this rule is for "constant" objects, or "copy on
write" objects. These include, but are not limited to: Int, Float,
Bool, Nil, Str. Their base values are immutable and are the heart
of object equality.
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-10 20:30:24 -07:00
|
|
|
// Conversion methods
|
WIP: Add imports and modules
This is a big change because it touches a lot of stuff, but here is the
overview:
* Import syntax:
```
import foo
import bar from foo
import bar from "foo.npp"
import bar, baz from foo
import * from foo
import "foo.npp"
```
* These are all valid imports. They should be pretty
straightforward, maybe with exception of the last item. If you are
importing a path directly, but not importing any members from it,
it does not insert anything into the current namespace, and just
executes the file. This is probably going to be unused but I want
to include it for completeness. We can always remove it later
before a hypothetical 1.0 release.
* The "from" keyword is only ever used as a keyword here, and I am
allowing it to be used as an identifier elsewhere. Don't export
it, because that's weird and wrong and won't work.
* Modules:
* Doing an `import foo` will look for "foo.npp" at compile-time,
relative to the importer's directory, parse it, and compile it.
The importer will then attempt to execute the module with the new
`EnterModule` op. This instruction will execute the module kind of
like a function, assigning the module's global namespace to an
object that you can pass around.
* `import bar from foo` and `import bar from "foo.npp"` et al syntax
is not currently implemented in the compiler.
* There is a new "Module" object that represents a potentially
un-initialized module. This can't be referred to directly in code.
* VM:
* The VM operates around Module objects now. If you want to "call" a
new module, you should call `enter_module`. This is how the main
chunk is invoked.
* TODOs:
* `exit_module` function in the VM
* Finish up module implementation in compiler
* Built-in modules
* Sub-modules - e.g. `import foo.bar` - how does naming work for
this?
* Module directories. In Python you have `foo/__init__.py` and in
Rust you have `foo/mod.rs`.
* Probably a "Namespace" object that explicitly denotes "this is an
imported module that you're dealing with"
* Tests, tests, tests
Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
2024-10-04 10:11:49 -07:00
|
|
|
// Operators
|
|
|
|
|
// Methods
|
2024-09-30 15:15:41 -07:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|