mirror of https://github.com/tildeio/helix
Merge pull request #128 from tildeio/consume-self
Allow consuming self in methods
This commit is contained in:
commit
c485529059
|
@ -21,7 +21,7 @@ appveyor = { repository = "tildeio/helix", branch = "master", service = "github"
|
|||
|
||||
[workspace]
|
||||
|
||||
members = ["examples/calculator", "examples/console", "examples/duration", "examples/membership", "examples/text_transform", "examples/turbo_blank"]
|
||||
members = ["examples/calculator", "examples/console", "examples/duration", "examples/membership", "examples/text_transform", "examples/turbo_blank", "examples/json_builder"]
|
||||
|
||||
[dependencies]
|
||||
libc = "0.2.0"
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
[package]
|
||||
name = "json_builder"
|
||||
version = "0.1.0"
|
||||
authors = ["Godfrey Chan <godfrey@tilde.io>"]
|
||||
|
||||
[lib]
|
||||
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[dependencies.helix]
|
||||
path = "../.."
|
||||
|
||||
[dependencies]
|
||||
serde_json = "*"
|
|
@ -0,0 +1,5 @@
|
|||
source 'https://rubygems.org'
|
||||
|
||||
gem 'helix_runtime', path: '../../ruby'
|
||||
gem 'rake', '~> 10.0'
|
||||
gem 'rspec', '~> 3.4'
|
|
@ -0,0 +1,39 @@
|
|||
PATH
|
||||
remote: ../../ruby
|
||||
specs:
|
||||
helix_runtime (0.7.1)
|
||||
rake (>= 10.0)
|
||||
thor (~> 0.19.4)
|
||||
tomlrb (~> 1.2.4)
|
||||
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
diff-lcs (1.3)
|
||||
rake (10.5.0)
|
||||
rspec (3.5.0)
|
||||
rspec-core (~> 3.5.0)
|
||||
rspec-expectations (~> 3.5.0)
|
||||
rspec-mocks (~> 3.5.0)
|
||||
rspec-core (3.5.4)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-expectations (3.5.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-mocks (3.5.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-support (3.5.0)
|
||||
thor (0.19.4)
|
||||
tomlrb (1.2.5)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
helix_runtime!
|
||||
rake (~> 10.0)
|
||||
rspec (~> 3.4)
|
||||
|
||||
BUNDLED WITH
|
||||
1.15.3
|
|
@ -0,0 +1,20 @@
|
|||
require 'bundler/setup'
|
||||
require 'helix_runtime/build_task'
|
||||
require 'rspec/core/rake_task'
|
||||
require_relative '../shared.rb'
|
||||
|
||||
# For Windows
|
||||
$stdout.sync = true
|
||||
|
||||
HelixRuntime::BuildTask.new do |t|
|
||||
t.build_root = File.expand_path("../..", __dir__)
|
||||
t.helix_lib_dir = File.expand_path("../../ruby/windows_build", __dir__)
|
||||
t.pre_build = HelixRuntime::Tests.pre_build
|
||||
end
|
||||
|
||||
RSpec::Core::RakeTask.new(:spec) do |t|
|
||||
t.verbose = false
|
||||
end
|
||||
|
||||
task :spec => :build
|
||||
task :default => :spec
|
|
@ -0,0 +1,2 @@
|
|||
require 'helix_runtime'
|
||||
require 'json_builder/native'
|
|
@ -0,0 +1,88 @@
|
|||
require "spec_helper"
|
||||
require "json"
|
||||
|
||||
describe "JsonBuilder" do
|
||||
let(:builder) { JsonBuilder.new }
|
||||
let(:json) { JSON.parse(builder.to_json) }
|
||||
|
||||
it "can add null" do
|
||||
builder["foo"] = nil
|
||||
expect(json).to eq({ "foo" => nil })
|
||||
end
|
||||
|
||||
it "can add booleans" do
|
||||
builder["foo"] = true
|
||||
builder["bar"] = false
|
||||
expect(json).to eq({ "foo" => true, "bar" => false })
|
||||
end
|
||||
|
||||
it "can add integers" do
|
||||
builder["foo"] = 12345
|
||||
builder["bar"] = -1_000_000
|
||||
expect(json).to eq({ "foo" => 12345, "bar" => -1_000_000 })
|
||||
end
|
||||
|
||||
it "can add floats" do
|
||||
builder["foo"] = 1.2345
|
||||
builder["bar"] = -1.0
|
||||
|
||||
expect(->{ builder["baz"] = Float::NAN }).to raise_error(TypeError)
|
||||
expect(->{ builder["baz"] = Float::INFINITY }).to raise_error(TypeError)
|
||||
|
||||
expect(json).to eq({ "foo" => 1.2345, "bar" => -1.0 })
|
||||
end
|
||||
|
||||
it "can add string" do
|
||||
builder["foo"] = "FOO"
|
||||
builder["bar"] = "BAR"
|
||||
expect(json).to eq({ "foo" => "FOO", "bar" => "BAR" })
|
||||
end
|
||||
|
||||
it "can add array" do
|
||||
foo = builder["foo"] = [nil, true, 12345, 1.2345, "FOO"]
|
||||
bar = builder["bar"] = [nil, false, -1_000_000, -1.0, "BAR"]
|
||||
expect(json).to eq({ "foo" => foo, "bar" => bar })
|
||||
end
|
||||
|
||||
it "can add hash" do
|
||||
foo = builder["foo"] = { "nil" => nil, "true" => true, "12345" => 12345, "1.2345" => 1.2345, "FOO" => "FOO" }
|
||||
bar = builder["bar"] = { "nil" => nil, "false" => false, "-1_000_000" => -1_000_000, "-1.0" => -1.0, "BAR" => "BAR" }
|
||||
expect(json).to eq({ "foo" => foo, "bar" => bar })
|
||||
end
|
||||
|
||||
it "can add nested builder" do
|
||||
builder["foo"] = JsonBuilder.new.tap { |inner| inner["foo"] = "FOO" }
|
||||
builder["bar"] = JsonBuilder.new.tap { |inner| inner["bar"] = "BAR" }
|
||||
expect(json).to eq({ "foo" => { "foo" => "FOO" }, "bar" => { "bar" => "BAR" } })
|
||||
end
|
||||
|
||||
it "can convert into a hash" do
|
||||
builder["foo"] = "FOO"
|
||||
builder["bar"] = nil
|
||||
expect(builder.to_h).to eq({ "foo" => "FOO", "bar" => nil })
|
||||
end
|
||||
|
||||
it "cannot be used once to_json is called" do
|
||||
expect(builder.to_json).to eq("{}")
|
||||
|
||||
expect(->{ builder["foo"] = nil }).to raise_error(RuntimeError, "Uninitialized JsonBuilder")
|
||||
expect(->{ builder.to_json }).to raise_error(RuntimeError, "Uninitialized JsonBuilder")
|
||||
expect(->{ builder.to_h }).to raise_error(RuntimeError, "Uninitialized JsonBuilder")
|
||||
end
|
||||
|
||||
it "cannot be used once to_h is called" do
|
||||
expect(builder.to_h).to eq({})
|
||||
|
||||
expect(->{ builder["foo"] = nil }).to raise_error(RuntimeError, "Uninitialized JsonBuilder")
|
||||
expect(->{ builder.to_json }).to raise_error(RuntimeError, "Uninitialized JsonBuilder")
|
||||
expect(->{ builder.to_h }).to raise_error(RuntimeError, "Uninitialized JsonBuilder")
|
||||
end
|
||||
|
||||
it "cannot be used once added to another builder" do
|
||||
JsonBuilder.new["foo"] = builder
|
||||
|
||||
expect(->{ builder["foo"] = nil }).to raise_error(RuntimeError, "Uninitialized JsonBuilder")
|
||||
expect(->{ builder.to_json }).to raise_error(RuntimeError, "Uninitialized JsonBuilder")
|
||||
expect(->{ builder.to_h }).to raise_error(RuntimeError, "Uninitialized JsonBuilder")
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
||||
require 'json_builder'
|
|
@ -0,0 +1,108 @@
|
|||
extern crate serde_json;
|
||||
|
||||
use super::{JsonValue, JsonBuilder};
|
||||
use helix::{FromRuby, CheckResult, ToRuby, ToRubyResult};
|
||||
use helix::sys::VALUE;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub enum CheckedJsonValue {
|
||||
Null,
|
||||
Boolean(<bool as FromRuby>::Checked),
|
||||
Integer(<i64 as FromRuby>::Checked),
|
||||
Float(f64),
|
||||
String(<String as FromRuby>::Checked),
|
||||
Array(<Vec<JsonValue> as FromRuby>::Checked),
|
||||
Object(<HashMap<String, JsonValue> as FromRuby>::Checked),
|
||||
Nested(<JsonBuilder as FromRuby>::Checked)
|
||||
}
|
||||
|
||||
impl FromRuby for JsonValue {
|
||||
type Checked = CheckedJsonValue;
|
||||
|
||||
fn from_ruby(value: VALUE) -> CheckResult<CheckedJsonValue> {
|
||||
if let Ok(_) = <()>::from_ruby(value) {
|
||||
Ok(CheckedJsonValue::Null)
|
||||
} else if let Ok(checked) = bool::from_ruby(value) {
|
||||
Ok(CheckedJsonValue::Boolean(checked))
|
||||
} else if let Ok(checked) = i64::from_ruby(value) {
|
||||
Ok(CheckedJsonValue::Integer(checked))
|
||||
} else if let Ok(checked) = f64::from_ruby(value) {
|
||||
let float = f64::from_checked(checked);
|
||||
|
||||
if float.is_normal() {
|
||||
Ok(CheckedJsonValue::Float(float))
|
||||
} else {
|
||||
type_error!(format!("Cannot convert {} into a JSON number", float))
|
||||
}
|
||||
} else if let Ok(checked) = String::from_ruby(value) {
|
||||
Ok(CheckedJsonValue::String(checked))
|
||||
} else if let Ok(checked) = Vec::<JsonValue>::from_ruby(value) {
|
||||
Ok(CheckedJsonValue::Array(checked))
|
||||
} else if let Ok(checked) = HashMap::<String, JsonValue>::from_ruby(value) {
|
||||
Ok(CheckedJsonValue::Object(checked))
|
||||
} else if let Ok(checked) = JsonBuilder::from_ruby(value) {
|
||||
Ok(CheckedJsonValue::Nested(checked))
|
||||
} else {
|
||||
type_error!(value, "a JSON value")
|
||||
}
|
||||
}
|
||||
|
||||
fn from_checked(checked: CheckedJsonValue) -> JsonValue {
|
||||
match checked {
|
||||
CheckedJsonValue::Null => JsonValue::Null,
|
||||
CheckedJsonValue::Boolean(c) => JsonValue::Boolean(FromRuby::from_checked(c)),
|
||||
CheckedJsonValue::Integer(c) => JsonValue::Integer(FromRuby::from_checked(c)),
|
||||
CheckedJsonValue::Float(c) => JsonValue::Float(c),
|
||||
CheckedJsonValue::String(c) => JsonValue::String(FromRuby::from_checked(c)),
|
||||
CheckedJsonValue::Array(c) => JsonValue::Array(FromRuby::from_checked(c)),
|
||||
CheckedJsonValue::Object(c) => JsonValue::Object(FromRuby::from_checked(c)),
|
||||
CheckedJsonValue::Nested(c) => JsonValue::Object(JsonBuilder::from_checked(c).to_hash_map())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToRuby for JsonValue {
|
||||
fn to_ruby(self) -> ToRubyResult {
|
||||
match self {
|
||||
JsonValue::Null => ().to_ruby(),
|
||||
JsonValue::Boolean(v) => v.to_ruby(),
|
||||
JsonValue::Integer(v) => v.to_ruby(),
|
||||
JsonValue::Float(v) => v.to_ruby(),
|
||||
JsonValue::String(v) => v.to_ruby(),
|
||||
JsonValue::Array(v) => v.to_ruby(),
|
||||
JsonValue::Object(v) => v.to_ruby(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use serde_json::{Value, Number};
|
||||
|
||||
pub trait ToSerde {
|
||||
fn to_serde(self) -> Value;
|
||||
}
|
||||
|
||||
impl ToSerde for JsonValue {
|
||||
fn to_serde(self) -> Value {
|
||||
match self {
|
||||
JsonValue::Null => Value::Null,
|
||||
JsonValue::Boolean(v) => Value::Bool(v),
|
||||
JsonValue::Integer(v) => Value::Number(Number::from(v)),
|
||||
JsonValue::Float(v) => Value::Number(Number::from_f64(v).unwrap()),
|
||||
JsonValue::String(v) => Value::String(v),
|
||||
JsonValue::Array(v) => v.to_serde(),
|
||||
JsonValue::Object(v) => v.to_serde(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSerde for Vec<JsonValue> {
|
||||
fn to_serde(self) -> Value {
|
||||
Value::Array(self.into_iter().map(|v| v.to_serde()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSerde for HashMap<String, JsonValue> {
|
||||
fn to_serde(self) -> Value {
|
||||
Value::Object(self.into_iter().map(|(k,v)| (k, v.to_serde())).collect())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#![recursion_limit="1024"]
|
||||
|
||||
#[macro_use]
|
||||
extern crate helix;
|
||||
extern crate serde_json;
|
||||
|
||||
mod coercion;
|
||||
|
||||
use coercion::ToSerde;
|
||||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
|
||||
#[derive(Clone,Debug)]
|
||||
pub enum JsonValue {
|
||||
Null,
|
||||
Boolean(bool),
|
||||
Integer(i64),
|
||||
Float(f64),
|
||||
String(String),
|
||||
Array(Vec<JsonValue>),
|
||||
Object(HashMap<String, JsonValue>)
|
||||
}
|
||||
|
||||
ruby! {
|
||||
pub class JsonBuilder {
|
||||
struct {
|
||||
entries: HashMap<String, JsonValue>
|
||||
}
|
||||
|
||||
def initialize(helix) {
|
||||
JsonBuilder { helix, entries: HashMap::new() }
|
||||
}
|
||||
|
||||
#[ruby_name="[]="]
|
||||
def put(&mut self, key: String, value: JsonValue) {
|
||||
self.entries.insert(key, value);
|
||||
}
|
||||
|
||||
def to_json(self) -> Result<String, String> {
|
||||
serde_json::to_string(&self.entries.to_serde())
|
||||
.map_err(|e| e.description().to_string())
|
||||
}
|
||||
|
||||
#[ruby_name="to_h"]
|
||||
def to_hash_map(self) -> HashMap<String, JsonValue> {
|
||||
self.entries
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,6 +40,32 @@ macro_rules! codegen_coercions {
|
|||
struct: $struct:tt,
|
||||
methods: $methods:tt
|
||||
}) => (
|
||||
impl $crate::FromRuby for $rust_name {
|
||||
type Checked = Box<$rust_name>;
|
||||
|
||||
fn from_ruby(value: $crate::sys::VALUE) -> $crate::CheckResult<Box<$rust_name>> {
|
||||
use $crate::{ToError, sys};
|
||||
|
||||
if unsafe { $rust_name != $crate::as_usize(sys::rb_obj_class(value)) } {
|
||||
type_error!(value, stringify!($rust_name));
|
||||
}
|
||||
|
||||
let ptr = unsafe { sys::Data_Get_Struct_Value(value) };
|
||||
|
||||
if ptr != ::std::ptr::null_mut() {
|
||||
Ok(unsafe { ::std::mem::transmute(ptr) })
|
||||
} else {
|
||||
Err(format!("Uninitialized {}", stringify!($rust_name)).to_error())
|
||||
}
|
||||
}
|
||||
|
||||
fn from_checked(mut checked: Box<$rust_name>) -> $rust_name {
|
||||
unsafe { $crate::sys::Data_Set_Struct_Value(checked.helix, ::std::ptr::null_mut()) };
|
||||
checked.helix = unsafe { $crate::sys::Qnil };
|
||||
*checked
|
||||
}
|
||||
}
|
||||
|
||||
impl_struct_to_rust!(&'a $rust_name, $rust_name);
|
||||
impl_struct_to_rust!(&'a mut $rust_name, $rust_name);
|
||||
|
||||
|
@ -54,6 +80,34 @@ macro_rules! codegen_coercions {
|
|||
);
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_struct_to_rust {
|
||||
($rust_name:ty, $helix_id:tt) => {
|
||||
impl<'a> $crate::FromRuby for $rust_name {
|
||||
type Checked = $rust_name;
|
||||
|
||||
fn from_ruby(value: $crate::sys::VALUE) -> $crate::CheckResult<$rust_name> {
|
||||
use $crate::{ToError, sys};
|
||||
|
||||
if unsafe { $helix_id != $crate::as_usize(sys::rb_obj_class(value)) } {
|
||||
type_error!(value, stringify!($helix_id));
|
||||
}
|
||||
|
||||
let ptr = unsafe { sys::Data_Get_Struct_Value(value) };
|
||||
|
||||
if ptr != ::std::ptr::null_mut() {
|
||||
Ok(unsafe { ::std::mem::transmute(ptr) })
|
||||
} else {
|
||||
Err(format!("Uninitialized {}", stringify!($helix_id)).to_error())
|
||||
}
|
||||
}
|
||||
|
||||
fn from_checked(checked: $rust_name) -> $rust_name {
|
||||
checked
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
|
@ -68,32 +122,3 @@ macro_rules! impl_to_ruby {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! impl_struct_to_rust {
|
||||
($rust_name:ty, $helix_id:tt) => {
|
||||
impl<'a> $crate::FromRuby for $rust_name {
|
||||
type Checked = $crate::CheckedValue<$rust_name>;
|
||||
|
||||
fn from_ruby(value: $crate::sys::VALUE) -> $crate::CheckResult<$crate::CheckedValue<$rust_name>> {
|
||||
use $crate::{CheckedValue, sys};
|
||||
use ::std::ffi::{CStr};
|
||||
|
||||
if unsafe { $helix_id == $crate::as_usize(sys::rb_obj_class(value)) } {
|
||||
if unsafe { $crate::sys::Data_Get_Struct_Value(value) == ::std::ptr::null_mut() } {
|
||||
type_error!(format!("Uninitialized {}", $crate::inspect(unsafe { sys::rb_obj_class(value) })))
|
||||
} else {
|
||||
Ok(unsafe { CheckedValue::new(value) })
|
||||
}
|
||||
} else {
|
||||
let val = unsafe { CStr::from_ptr(sys::rb_obj_classname(value)).to_string_lossy() };
|
||||
type_error!(format!("No implicit conversion of {} into {}", val, $crate::inspect(unsafe { sys::rb_obj_class(value) })))
|
||||
}
|
||||
}
|
||||
|
||||
fn from_checked(checked: $crate::CheckedValue<$rust_name>) -> $rust_name {
|
||||
unsafe { ::std::mem::transmute($crate::sys::Data_Get_Struct_Value(checked.to_value())) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -328,7 +328,7 @@ macro_rules! parse {
|
|||
assert_has_struct!($class, "Cannot define `initialize` without a `struct`");
|
||||
|
||||
parse! {
|
||||
state: parse_arguments_helix,
|
||||
state: parse_arguments_initialize,
|
||||
buffer: { $($args)* },
|
||||
stack: {
|
||||
class_body: { $($rest)* },
|
||||
|
@ -348,7 +348,7 @@ macro_rules! parse {
|
|||
}
|
||||
} => {
|
||||
parse! {
|
||||
state: parse_arguments_self,
|
||||
state: parse_arguments,
|
||||
buffer: { $($args)* },
|
||||
stack: {
|
||||
rust_name: $rust_name,
|
||||
|
@ -359,16 +359,21 @@ macro_rules! parse {
|
|||
}
|
||||
};
|
||||
|
||||
// STATE: parse_arguments_helix
|
||||
// STATE: parse_arguments_initialize
|
||||
|
||||
{
|
||||
state: parse_arguments_helix,
|
||||
buffer: { $helix_arg:tt $($rest:tt)* },
|
||||
stack: { $($stack:tt)* }
|
||||
state: parse_arguments_initialize,
|
||||
buffer: { $helix_arg:tt, $($args:tt)+ },
|
||||
stack: {
|
||||
class_body: $class_body:tt,
|
||||
$($stack:tt)*
|
||||
}
|
||||
} => {
|
||||
assert_valid_helix_arg!($helix_arg);
|
||||
|
||||
parse! {
|
||||
state: parse_arguments_consume_possible_comma,
|
||||
buffer: { $($rest)* },
|
||||
state: parse_return_type,
|
||||
buffer: $class_body,
|
||||
stack: {
|
||||
method: {
|
||||
type: initializer,
|
||||
|
@ -378,7 +383,7 @@ macro_rules! parse {
|
|||
ownership: { },
|
||||
name: $helix_arg
|
||||
},
|
||||
args: uninitialized,
|
||||
args: [ $($args)* ],
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
},
|
||||
|
@ -387,22 +392,54 @@ macro_rules! parse {
|
|||
}
|
||||
};
|
||||
|
||||
// STATE: parse_arguments_self
|
||||
{
|
||||
state: parse_arguments_initialize,
|
||||
buffer: { $helix_arg:tt },
|
||||
stack: {
|
||||
class_body: $class_body:tt,
|
||||
$($stack:tt)*
|
||||
}
|
||||
} => {
|
||||
assert_valid_helix_arg!($helix_arg);
|
||||
|
||||
parse! {
|
||||
state: parse_return_type,
|
||||
buffer: $class_body,
|
||||
stack: {
|
||||
method: {
|
||||
type: initializer,
|
||||
rust_name: initialize,
|
||||
ruby_name: { "initialize" },
|
||||
self: {
|
||||
ownership: { },
|
||||
name: $helix_arg
|
||||
},
|
||||
args: [ ],
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
},
|
||||
$($stack)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// STATE: parse_arguments
|
||||
|
||||
{
|
||||
state: parse_arguments_self,
|
||||
buffer: { &mut $self_arg:tt $($rest:tt)* },
|
||||
state: parse_arguments,
|
||||
buffer: { &mut $self_arg:tt, $($args:tt)+ },
|
||||
stack: {
|
||||
rust_name: $rust_name:tt,
|
||||
ruby_name: $ruby_name:tt,
|
||||
class_body: $class_body:tt,
|
||||
$($stack:tt)*
|
||||
}
|
||||
} => {
|
||||
assert_valid_self_arg!($self_arg);
|
||||
|
||||
parse! {
|
||||
state: parse_arguments_consume_possible_comma,
|
||||
buffer: { $($rest)* },
|
||||
state: parse_return_type,
|
||||
buffer: $class_body,
|
||||
stack: {
|
||||
method: {
|
||||
type: instance_method,
|
||||
|
@ -412,7 +449,7 @@ macro_rules! parse {
|
|||
ownership: { &mut },
|
||||
name: $self_arg
|
||||
},
|
||||
args: uninitialized,
|
||||
args: [ $($args)* ],
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
},
|
||||
|
@ -422,19 +459,53 @@ macro_rules! parse {
|
|||
};
|
||||
|
||||
{
|
||||
state: parse_arguments_self,
|
||||
buffer: { & $self_arg:tt $($rest:tt)* },
|
||||
state: parse_arguments,
|
||||
buffer: { &mut $self_arg:tt },
|
||||
stack: {
|
||||
rust_name: $rust_name:tt,
|
||||
ruby_name: $ruby_name:tt,
|
||||
class_body: $class_body:tt,
|
||||
$($stack:tt)*
|
||||
}
|
||||
} => {
|
||||
assert_valid_self_arg!($self_arg);
|
||||
|
||||
parse! {
|
||||
state: parse_arguments_consume_possible_comma,
|
||||
buffer: { $($rest)* },
|
||||
state: parse_return_type,
|
||||
buffer: $class_body,
|
||||
stack: {
|
||||
method: {
|
||||
type: instance_method,
|
||||
rust_name: $rust_name,
|
||||
ruby_name: $ruby_name,
|
||||
self: {
|
||||
ownership: { &mut },
|
||||
name: $self_arg
|
||||
},
|
||||
args: [ ],
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
},
|
||||
$($stack)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
state: parse_arguments,
|
||||
buffer: { & $self_arg:tt, $($args:tt)+ },
|
||||
stack: {
|
||||
rust_name: $rust_name:tt,
|
||||
ruby_name: $ruby_name:tt,
|
||||
class_body: $class_body:tt,
|
||||
$($stack:tt)*
|
||||
}
|
||||
} => {
|
||||
assert_valid_self_arg!($self_arg);
|
||||
|
||||
parse! {
|
||||
state: parse_return_type,
|
||||
buffer: $class_body,
|
||||
stack: {
|
||||
method: {
|
||||
type: instance_method,
|
||||
|
@ -444,7 +515,7 @@ macro_rules! parse {
|
|||
ownership: { & },
|
||||
name: $self_arg
|
||||
},
|
||||
args: uninitialized,
|
||||
args: [ $($args)* ],
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
},
|
||||
|
@ -454,24 +525,30 @@ macro_rules! parse {
|
|||
};
|
||||
|
||||
{
|
||||
state: parse_arguments_self,
|
||||
buffer: $buffer:tt,
|
||||
state: parse_arguments,
|
||||
buffer: { & $self_arg:tt },
|
||||
stack: {
|
||||
rust_name: $rust_name:tt,
|
||||
ruby_name: $ruby_name:tt,
|
||||
class_body: $class_body:tt,
|
||||
$($stack:tt)*
|
||||
}
|
||||
} => {
|
||||
assert_valid_self_arg!($self_arg);
|
||||
|
||||
parse! {
|
||||
state: parse_arguments,
|
||||
buffer: $buffer,
|
||||
state: parse_return_type,
|
||||
buffer: $class_body,
|
||||
stack: {
|
||||
method: {
|
||||
type: class_method,
|
||||
type: instance_method,
|
||||
rust_name: $rust_name,
|
||||
ruby_name: $ruby_name,
|
||||
self: (),
|
||||
args: uninitialized,
|
||||
self: {
|
||||
ownership: { & },
|
||||
name: $self_arg
|
||||
},
|
||||
args: [ ],
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
},
|
||||
|
@ -480,47 +557,78 @@ macro_rules! parse {
|
|||
}
|
||||
};
|
||||
|
||||
// STATE: parse_arguments_consume_possible_comma
|
||||
|
||||
{
|
||||
state: parse_arguments_consume_possible_comma,
|
||||
buffer: { , $($rest:tt)+ },
|
||||
stack: $stack:tt
|
||||
{
|
||||
state: parse_arguments,
|
||||
buffer: { $self_arg:tt, $($args:tt)+ },
|
||||
stack: {
|
||||
rust_name: $rust_name:tt,
|
||||
ruby_name: $ruby_name:tt,
|
||||
class_body: $class_body:tt,
|
||||
$($stack:tt)*
|
||||
}
|
||||
} => {
|
||||
assert_valid_self_arg!($self_arg);
|
||||
|
||||
parse! {
|
||||
state: parse_arguments,
|
||||
buffer: { $($rest)+ },
|
||||
stack: $stack
|
||||
state: parse_return_type,
|
||||
buffer: $class_body,
|
||||
stack: {
|
||||
method: {
|
||||
type: instance_method,
|
||||
rust_name: $rust_name,
|
||||
ruby_name: $ruby_name,
|
||||
self: {
|
||||
ownership: { },
|
||||
name: $self_arg
|
||||
},
|
||||
args: [ $($args)* ],
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
},
|
||||
$($stack)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
{
|
||||
state: parse_arguments_consume_possible_comma,
|
||||
buffer: { },
|
||||
stack: $stack:tt
|
||||
state: parse_arguments,
|
||||
buffer: { $self_arg:tt },
|
||||
stack: {
|
||||
rust_name: $rust_name:tt,
|
||||
ruby_name: $ruby_name:tt,
|
||||
class_body: $class_body:tt,
|
||||
$($stack:tt)*
|
||||
}
|
||||
} => {
|
||||
assert_valid_self_arg!($self_arg);
|
||||
|
||||
parse! {
|
||||
state: parse_arguments,
|
||||
buffer: { },
|
||||
stack: $stack
|
||||
state: parse_return_type,
|
||||
buffer: $class_body,
|
||||
stack: {
|
||||
method: {
|
||||
type: instance_method,
|
||||
rust_name: $rust_name,
|
||||
ruby_name: $ruby_name,
|
||||
self: {
|
||||
ownership: { },
|
||||
name: $self_arg
|
||||
},
|
||||
args: [ ],
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
},
|
||||
$($stack)*
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// STATE: parse_arguments
|
||||
|
||||
{
|
||||
state: parse_arguments,
|
||||
buffer: { $($args:tt)* },
|
||||
stack: {
|
||||
method: {
|
||||
type: $type:tt,
|
||||
rust_name: $rust_name:tt,
|
||||
ruby_name: $ruby_name:tt,
|
||||
self: $self:tt,
|
||||
args: uninitialized,
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
},
|
||||
rust_name: $rust_name:tt,
|
||||
ruby_name: $ruby_name:tt,
|
||||
class_body: $class_body:tt,
|
||||
$($stack:tt)*
|
||||
}
|
||||
|
@ -530,10 +638,10 @@ macro_rules! parse {
|
|||
buffer: $class_body,
|
||||
stack: {
|
||||
method: {
|
||||
type: $type,
|
||||
type: class_method,
|
||||
rust_name: $rust_name,
|
||||
ruby_name: $ruby_name,
|
||||
self: $self,
|
||||
self: (),
|
||||
args: [ $($args)* ],
|
||||
ret: uninitialized,
|
||||
body: uninitialized
|
||||
|
@ -774,6 +882,12 @@ macro_rules! assert_has_struct {
|
|||
{ { struct: $struct:tt }, $($message:expr),* } => {};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! assert_valid_helix_arg {
|
||||
(helix) => {};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! assert_valid_self_arg {
|
||||
|
|
Loading…
Reference in New Issue