From 2aca4a7512700a6347c0146ed464adae1917f1c1 Mon Sep 17 00:00:00 2001 From: Carl Masak Date: Mon, 25 Jun 2018 10:19:35 +0200 Subject: [PATCH] Rename Object to Dict It's more like Dict already than like Object. There are a few things to straighten out here that need to be fixed before this is mergeable to master -- notably, the whole `new` syntax needs to work with objects, not with dicts. But this is an encouraging start. Closes #184. --- examples/in.007 | 8 +-- lib/_007/Builtins.pm6 | 2 +- lib/_007/Equal.pm6 | 2 +- lib/_007/Parser/Actions.pm6 | 27 ++++++----- lib/_007/Parser/Syntax.pm6 | 8 +-- lib/_007/Q.pm6 | 17 +++---- lib/_007/Runtime.pm6 | 20 ++++---- lib/_007/Val.pm6 | 97 +++++++++---------------------------- self-host/runtime.007 | 2 +- t/builtins/methods.t | 2 +- t/builtins/operators.t | 8 +-- t/features/class.t | 12 ++--- t/features/objects.t | 11 ++--- t/features/quasi.t | 9 ++-- 14 files changed, 86 insertions(+), 139 deletions(-) diff --git a/examples/in.007 b/examples/in.007 index c81fb137..9151e15a 100644 --- a/examples/in.007 +++ b/examples/in.007 @@ -7,7 +7,7 @@ func infix:(value, container) { } return false; } - else if container ~~ Object { + else if container ~~ Dict { return container.has(value); } else if container ~~ Str { @@ -15,7 +15,7 @@ func infix:(value, container) { } else { throw new Exception { - message: "Wrong type to infix:. Expected Array or Object or Str, was " ~ type(container), + message: "Wrong type to infix:. Expected Array or Dict or Str, was " ~ type(container), }; } } @@ -29,7 +29,7 @@ func infix:(value, container) { } return true; } - else if container ~~ Object { + else if container ~~ Dict { return !container.has(value); } else if container ~~ Str { @@ -37,7 +37,7 @@ func infix:(value, container) { } else { throw new Exception { - message: "Wrong type to infix:. Expected Array or Object or Str, was " ~ type(container), + message: "Wrong type to infix:. Expected Array or Dict or Str, was " ~ type(container), }; } } diff --git a/lib/_007/Builtins.pm6 b/lib/_007/Builtins.pm6 index b3b0eaf1..7833db99 100644 --- a/lib/_007/Builtins.pm6 +++ b/lib/_007/Builtins.pm6 @@ -358,7 +358,7 @@ my ¶meter = { Q::Parameter.new(:identifier(Q::Identifier.new(:name(Val::Str. default { die "Unknown type {.value.^name}" } }); -my $builtins-pad = Val::Object.new; +my $builtins-pad = Val::Dict.new; for @builtins -> Pair (:key($name), :$value) { $builtins-pad.properties{$name} = $value; } diff --git a/lib/_007/Equal.pm6 b/lib/_007/Equal.pm6 index 68c1d945..adb7c658 100644 --- a/lib/_007/Equal.pm6 +++ b/lib/_007/Equal.pm6 @@ -21,7 +21,7 @@ multi equal-value(Val::Array $l, Val::Array $r) { [&&] $l.elements == $r.elements, |(^$l.elements).map(&equal-at-index); } -multi equal-value(Val::Object $l, Val::Object $r) { +multi equal-value(Val::Dict $l, Val::Dict $r) { if %*equality-seen{$l.WHICH} && %*equality-seen{$r.WHICH} { return $l === $r; } diff --git a/lib/_007/Parser/Actions.pm6 b/lib/_007/Parser/Actions.pm6 index fcd9e367..5339f508 100644 --- a/lib/_007/Parser/Actions.pm6 +++ b/lib/_007/Parser/Actions.pm6 @@ -270,7 +270,7 @@ class _007::Parser::Actions { } if $expansion ~~ Q::StatementList { - $*runtime.enter($*runtime.current-frame, Val::Object.new, $expansion); + $*runtime.enter($*runtime.current-frame, Val::Dict.new, $expansion); $expansion = Q::Block.new( :parameterlist(Q::ParameterList.new()) :statementlist($expansion)); @@ -340,7 +340,7 @@ class _007::Parser::Actions { my $declname = $decltype.^name.subst(/ .* '::'/, "").lc; die X::Assignment::ReadOnly.new(:$declname, :$symbol) unless $decltype.is-assignable; - %*assigned{$frame.id ~ $symbol}++; + %*assigned{$frame.WHICH ~ $symbol}++; } } } @@ -656,11 +656,10 @@ class _007::Parser::Actions { my $type-obj = $type.type; my $name = $type-obj.^name.subst("::", ".", :g); - if $type-obj !=== Val::Object { + if $type-obj !=== Val::Dict { if is-role($type-obj) { die X::Uninstantiable.new(:$name); } - sub aname($attr) { $attr.name.substr(2) } my %known-properties = $type-obj.attributes.map({ aname($_) => 1 }); for $.ast.properties.elements -> $p { @@ -678,12 +677,16 @@ class _007::Parser::Actions { } } - make Q::Term::Object.new(:$type, :propertylist($.ast)); + make Q::Term::Dict.new( + :$type, + :propertylist($.ast)); } - method term:object ($/) { - make Q::Term::Object.new( - :type(Val::Type.of(Val::Object)), + method term:dict ($/) { + my $type = Val::Type.of(Val::Dict); + + make Q::Term::Dict.new( + :$type, :propertylist($.ast)); } @@ -846,7 +849,7 @@ sub check(Q $ast, $runtime) is export { :statementlist($func.block.statementlist), :$outer-frame ); - $runtime.enter($outer-frame, Val::Object.new, $func.block.statementlist, $val); + $runtime.enter($outer-frame, Val::Dict.new, $func.block.statementlist, $val); handle($func.block); $runtime.leave(); @@ -861,7 +864,7 @@ sub check(Q $ast, $runtime) is export { :statementlist($macro.block.statementlist), :$outer-frame ); - $runtime.enter($outer-frame, Val::Object.new, $macro.block.statementlist, $val); + $runtime.enter($outer-frame, Val::Dict.new, $macro.block.statementlist, $val); handle($macro.block); $runtime.leave(); @@ -881,14 +884,14 @@ sub check(Q $ast, $runtime) is export { } multi handle(Q::Block $block) { - $runtime.enter($runtime.current-frame, Val::Object.new, Q::StatementList.new); + $runtime.enter($runtime.current-frame, Val::Dict.new, Q::StatementList.new); handle($block.parameterlist); handle($block.statementlist); $block.static-lexpad = $runtime.current-frame.properties; $runtime.leave(); } - multi handle(Q::Term::Object $object) { + multi handle(Q::Term::Dict $object) { handle($object.propertylist); } diff --git a/lib/_007/Parser/Syntax.pm6 b/lib/_007/Parser/Syntax.pm6 index c8a5f56e..c778a3f7 100644 --- a/lib/_007/Parser/Syntax.pm6 +++ b/lib/_007/Parser/Syntax.pm6 @@ -19,7 +19,7 @@ grammar _007::Parser::Syntax { token newpad { { $*parser.push-opscope; @*declstack.push(@*declstack ?? @*declstack[*-1].clone !! {}); - $*runtime.enter($*runtime.current-frame, Val::Object.new, Q::StatementList.new); + $*runtime.enter($*runtime.current-frame, Val::Dict.new, Q::StatementList.new); } } token finishpad { { @@ -40,7 +40,7 @@ grammar _007::Parser::Syntax { if $*runtime.declared-locally($symbol); my $frame = $*runtime.current-frame(); die X::Redeclaration::Outer.new(:$symbol) - if %*assigned{$frame.id ~ $symbol}; + if %*assigned{$frame.WHICH ~ $symbol}; my $identifier = Q::Identifier.new( :name(Val::Str.new(:value($symbol))), :$frame); @@ -223,7 +223,7 @@ grammar _007::Parser::Syntax { || "<" <.ws> $=["Q.PropertyList"] ">" <.ws> '{' <.ws> <.ws> '}' || "<" <.ws> $=["Q.Term"] ">" <.ws> '{' <.ws> <.ws> '}' || "<" <.ws> $=["Q.Term.Array"] ">" <.ws> '{' <.ws> <.ws> '}' - || "<" <.ws> $=["Q.Term.Object"] ">" <.ws> '{' <.ws> <.ws> '}' + || "<" <.ws> $=["Q.Term.Dict"] ">" <.ws> '{' <.ws> <.ws> '}' || "<" <.ws> $=["Q.Term.Quasi"] ">" <.ws> '{' <.ws> <.ws> '}' || "<" <.ws> $=["Q.Trait"] ">" <.ws> '{' <.ws> <.ws> '}' || "<" <.ws> $=["Q.TraitList"] ">" <.ws> '{' <.ws> <.ws> '}' @@ -251,7 +251,7 @@ grammar _007::Parser::Syntax { }> <.ws> '{' ~ '}' } - token term:object { + token term:dict { '{' ~ '}' } token term:identifier { diff --git a/lib/_007/Q.pm6 b/lib/_007/Q.pm6 index 7cdcb6ad..6492a30b 100644 --- a/lib/_007/Q.pm6 +++ b/lib/_007/Q.pm6 @@ -288,12 +288,11 @@ class Q::Term::Array does Q::Term { } } -### ### Q::Term::Object +### ### Q::Term::Dict ### -### An object. Object terms consist of an optional *type*, and a property list -### with zero or more key/value pairs. +### A dict. Dict terms consist of an entry list with zero or more key/value pairs. ### -class Q::Term::Object does Q::Term { +class Q::Term::Dict does Q::Term { has Val::Type $.type; has $.propertylist; @@ -391,7 +390,7 @@ class Q::Term::Func does Q::Term does Q::Declaration { class Q::Block does Q { has $.parameterlist; has $.statementlist; - has Val::Object $.static-lexpad is rw = Val::Object.new; + has Val::Dict $.static-lexpad is rw = Val::Dict.new; # XXX has $.frame is rw; @@ -530,7 +529,7 @@ class Q::Postfix::Index is Q::Postfix { if $index.value < 0; return .elements[$index.value]; } - when Val::Object | Val::Func | Q { + when Val::Dict | Val::Func | Q { my $property = $.index.eval($runtime); die X::Subscript::NonString.new if $property !~~ Val::Str; @@ -553,7 +552,7 @@ class Q::Postfix::Index is Q::Postfix { if $index.value < 0; .elements[$index.value] = $value; } - when Val::Object | Q { + when Val::Dict | Q { my $property = $.index.eval($runtime); die X::Subscript::NonString.new if $property !~~ Val::Str; @@ -602,7 +601,7 @@ class Q::Postfix::Property is Q::Postfix { method put-value($value, $runtime) { given $.operand.eval($runtime) { - when Val::Object | Q { + when Val::Dict | Q { my $propname = $.property.name.value; $runtime.put-property($_, $propname, $value); } @@ -666,7 +665,7 @@ class Q::Term::Quasi does Q::Term { if $thing ~~ Val::Array; return $thing.new(:properties(%($thing.properties.map({ .key => interpolate(.value) })))) - if $thing ~~ Val::Object; + if $thing ~~ Val::Dict; return $thing if $thing ~~ Val; diff --git a/lib/_007/Runtime.pm6 b/lib/_007/Runtime.pm6 index 9dbd3590..2c4d7527 100644 --- a/lib/_007/Runtime.pm6 +++ b/lib/_007/Runtime.pm6 @@ -3,7 +3,7 @@ use _007::Q; use _007::Builtins; use _007::Equal; -constant NO_OUTER = Val::Object.new; +constant NO_OUTER = Val::Dict.new; constant RETURN_TO = Q::Identifier.new( :name(Val::Str.new(:value("--RETURN-TO--"))), :frame(NONE)); @@ -23,7 +23,7 @@ class _007::Runtime { submethod BUILD(:$!input, :$!output, :@!arguments) { $!builtin-opscope = opscope(); - $!builtin-frame = Val::Object.new(:properties( + $!builtin-frame = Val::Dict.new(:properties( :outer-frame(NO_OUTER), :pad(builtins-pad())) ); @@ -76,7 +76,7 @@ class _007::Runtime { } method enter($outer-frame, $static-lexpad, $statementlist, $routine?) { - my $frame = Val::Object.new(:properties(:$outer-frame, :pad(Val::Object.new))); + my $frame = Val::Dict.new(:properties(:$outer-frame, :pad(Val::Dict.new))); @!frames.push($frame); for $static-lexpad.properties.kv -> $name, $value { my $identifier = Q::Identifier.new( @@ -162,7 +162,7 @@ class _007::Runtime { method declare-var(Q::Identifier $identifier, $value?) { my $name = $identifier.name.value; - my Val::Object $frame = $identifier.frame ~~ Val::None + my Val::Dict $frame = $identifier.frame ~~ Val::None ?? self.current-frame !! $identifier.frame; $frame.properties.properties{$name} = $value // NONE; @@ -258,7 +258,7 @@ class _007::Runtime { if $thing ~~ Val::Array; return $thing.new(:properties(%($thing.properties.map(.key => interpolate(.value))))) - if $thing ~~ Val::Object; + if $thing ~~ Val::Dict; return $thing if $thing ~~ Val; @@ -376,7 +376,7 @@ class _007::Runtime { return Val::Str.new(:value($obj.elements.join($sep.value.Str))); }); } - elsif $obj ~~ Val::Object && $propname eq "size" { + elsif $obj ~~ Val::Dict && $propname eq "size" { return builtin(sub size() { return Val::Int.new(:value($obj.properties.elems)); }); @@ -512,7 +512,7 @@ class _007::Runtime { elsif $obj ~~ Val::Func && $propname eq any { return $obj."$propname"(); } - elsif $obj ~~ (Q | Val::Object) && ($obj.properties{$propname} :exists) { + elsif $obj ~~ (Q | Val::Dict) && ($obj.properties{$propname} :exists) { return $obj.properties{$propname}; } elsif $propname eq "get" { @@ -532,7 +532,7 @@ class _007::Runtime { # XXX: problem: we're not lying hard enough here. we're missing # both Q objects, which are still hard-coded into the # substrate, and the special-cased properties - # + # my $value = $obj.properties{$prop.value} :exists; return Val::Bool.new(:$value); }); @@ -638,8 +638,8 @@ class _007::Runtime { if $obj ~~ Q { die "We don't handle assigning to Q object properties yet"; } - elsif $obj !~~ Val::Object { - die "We don't handle assigning to non-Val::Object types yet"; + elsif $obj !~~ Val::Dict { + die "We don't handle assigning to non-Val::Dict types yet"; } else { $obj.properties{$propname} = $newvalue; diff --git a/lib/_007/Val.pm6 b/lib/_007/Val.pm6 index 408e6437..7fa51059 100644 --- a/lib/_007/Val.pm6 +++ b/lib/_007/Val.pm6 @@ -358,95 +358,44 @@ class Val::Array does Val { our $global-object-id = 0; -### ### Object +### ### Dict ### -### A mutable unordered collection of key/value properties. An object -### contains zero or more such properties, each with a unique string +### A mutable unordered collection of key/value entries. A dict +### contains zero or more such entries, each with a unique string ### name. ### -### The way to create an object from scratch is to use the object term +### The way to create a dict from scratch is to use the dict term ### syntax: ### -### my o1 = { foo: 42 }; # autoquoted key -### my o2 = { "foo": 42 }; # string key -### say(o1 == o2); # --> `true` -### my foo = 42; -### my o3 = { foo }; # property shorthand -### say(o1 == o3); # --> `true` +### my d1 = { foo: 42 }; # autoquoted key +### my d2 = { "foo": 42 }; # string key +### say(d1 == d2); # --> `true` ### -### my o4 = { -### greet: func () { -### return "hi!"; -### } -### }; -### my o5 = { -### greet() { # method shorthand -### return "hi!"; -### } -### }; -### say(o4.greet() == o5.greet()); # --> `true` -### -### All of the above will create objects of type `Object`, which is -### the topmost type in the type system. `Object` also has the special -### property that it can accept any set of keys. -### -### say(type({})); # --> `` -### -### There are also two ways to create a new, similar object from an old one. -### -### my o6 = { -### name: "James", -### job: "librarian" -### }; -### my o7 = o6.update({ -### job: "secret agent" -### }); -### say(o7); # --> `{job: "secret agent", name: "James"}` -### -### my o8 = { -### name: "Blofeld" -### }; -### my o9 = o8.extend({ -### job: "supervillain" -### }); -### say(o9); # --> `{job: "supervillain", name: "Blofeld"}` -### -### There's a way to extract an array of an object's keys. The order of the keys in +### There's a way to extract an array of a dict's keys. The order of the keys in ### this list is not defined and may even change from call to call. ### -### my o10 = { +### my d3 = { ### one: 1, ### two: 2, ### three: 3 ### }; -### say(o10.keys().sort()); # --> `["one", "three", "two"]` +### say(d3.keys().sort()); # --> `["one", "three", "two"]` ### -### You can also ask whether a key exists on an object. +### You can also ask whether an entry exists in a dict. ### -### my o11 = { +### my d4 = { ### foo: 42, ### bar: none ### }; -### say(o11.has("foo")); # --> `true` -### say(o11.has("bar")); # --> `true` -### say(o11.has("bazinga")); # --> `false` +### say(d4.has("foo")); # --> `true` +### say(d4.has("bar")); # --> `true` +### say(d4.has("bazinga")); # --> `false` ### -### Note that the criterion is whether the *key* exists, not whether the +### Note that the criterion is whether the *entry* exists, not whether the ### corresponding value is defined. ### -### Each object has a unique ID, corresponding to references in other -### languages. Comparison of objects happens by comparing keys and values, -### not by reference. If you want to do a reference comparison, you need -### to use the `.id` property: -### -### my o12 = { foo: 5 }; -### my o13 = { foo: 5 }; # same key/value but different reference -### say(o12 == o13); # --> `true` -### say(o12.id == o13.id); # --> `false` -### -class Val::Object does Val { +class Val::Dict does Val { has %.properties{Str}; - has $.id = $global-object-id++; method quoted-Str { if %*stringification-seen{self.WHICH}++ { @@ -473,11 +422,11 @@ class Val::Object does Val { ### ### say(type(007)); # --> `` ### say(type("Bond")); # --> `` -### say(type({})); # --> `` +### say(type({})); # --> `` ### say(type(type({}))); # --> `` ### ### 007 comes with a number of built-in types: `None`, `Bool`, `Int`, -### `Str`, `Array`, `Object`, `Regex`, `Type`, `Block`, `Sub`, `Macro`, +### `Str`, `Array`, `Dict`, `Regex`, `Type`, `Block`, `Sub`, `Macro`, ### and `Exception`. ### ### There's also a whole hierarchy of Q types, which describe parts of @@ -526,7 +475,7 @@ class Val::Type does Val { } method create(@properties) { - if $.type ~~ Val::Object { + if $.type ~~ Val::Dict { return $.type.new(:@properties); } elsif $.type ~~ Val::Int | Val::Str { @@ -578,8 +527,8 @@ class Val::Func does Val { has &.hook = Callable; has $.parameterlist; has $.statementlist; - has Val::Object $.static-lexpad is rw = Val::Object.new; - has Val::Object $.outer-frame; + has Val::Dict $.static-lexpad is rw = Val::Dict.new; + has Val::Dict $.outer-frame; method new-builtin(&hook, Str $name, $parameterlist, $statementlist) { self.bless(:name(Val::Str.new(:value($name))), :&hook, :$parameterlist, :$statementlist); @@ -639,7 +588,7 @@ class Helper { when Val::Str { .value } when Val::Regex { .quoted-Str } when Val::Array { .quoted-Str } - when Val::Object { .quoted-Str } + when Val::Dict { .quoted-Str } when Val::Type { "" } when Val::Macro { "" } when Val::Func { "" } diff --git a/self-host/runtime.007 b/self-host/runtime.007 index 5ecdcd0e..a9b49f67 100644 --- a/self-host/runtime.007 +++ b/self-host/runtime.007 @@ -203,7 +203,7 @@ my Runtime = { }, "Q.Prefix": func(op) { }, - "Q.Term.Object": func(term) { + "Q.Term.Dict": func(term) { }, "Q.Term.Quasi": func(term) { }, diff --git a/t/builtins/methods.t b/t/builtins/methods.t index 4a1a439f..6248e9d9 100644 --- a/t/builtins/methods.t +++ b/t/builtins/methods.t @@ -333,7 +333,7 @@ use _007::Test; { my $program = q:to/./; - say(Object.create([["foo", 42]])); + say(Dict.create([["foo", 42]])); . outputs $program, qq[\{foo: 42\}\n], "Type.create() method to create an Object"; diff --git a/t/builtins/operators.t b/t/builtins/operators.t index a5d2e6a6..cfca05ef 100644 --- a/t/builtins/operators.t +++ b/t/builtins/operators.t @@ -545,10 +545,10 @@ use _007::Test; { my $program = q:to/./; - my q = {}; say(q ~~ Object) + my q = {}; say(q ~~ Dict) . - outputs $program, "true\n", "typecheck works for Val::Object"; + outputs $program, "true\n", "typecheck works for Val::Dict"; } { @@ -557,9 +557,9 @@ use _007::Test; say(quasi { + } !~~ Q.Prefix); say(42 !~~ Int); say([4, 2] !~~ Array); - say({} !~~ Object); + say({} !~~ Dict); say(42 !~~ Array); - say([4, 2] !~~ Object); + say([4, 2] !~~ Dict); say({} !~~ Int); . diff --git a/t/features/class.t b/t/features/class.t index e4907e79..e430fced 100644 --- a/t/features/class.t +++ b/t/features/class.t @@ -40,20 +40,20 @@ ensure-feature-flag("CLASS"); { my $program = q:to/./; - my BuiltinObject; + my BuiltinDict; BEGIN { - BuiltinObject = Object; + BuiltinDict = Dict; } { - class Object { + class Dict { } - say({} ~~ BuiltinObject); - say({} ~~ Object); + say({} ~~ BuiltinDict); + say({} ~~ Dict); } . - outputs $program, "true\nfalse\n", "the `\{\}` syntax uses the built-in Object, even when overridden"; + outputs $program, "true\nfalse\n", "the `\{\}` syntax uses the built-in Dict, even when overridden"; } { diff --git a/t/features/objects.t b/t/features/objects.t index 7d4b87b2..4ca05d82 100644 --- a/t/features/objects.t +++ b/t/features/objects.t @@ -72,7 +72,7 @@ use _007::Test; parse-error $program, X::Property::Duplicate, - "can't have duplicate properties (#85)"; + "can't have duplicate properties (#85) (II)"; } { @@ -87,14 +87,11 @@ use _007::Test; say(o.update({ bond: 8 })); say({ x: 1 }.extend({ y: 2 })); - - my n = o.id; - say("id"); . outputs $program, - qq[true\nfalse\n7\n\{bond: 8, james: "bond"\}\n\{x: 1, y: 2\}\nid\n], + qq[true\nfalse\n7\n\{bond: 8, james: "bond"\}\n\{x: 1, y: 2\}\n], "built-in pseudo-inherited methods on objects"; } @@ -137,7 +134,7 @@ use _007::Test; { my $program = q:to/./; - my q = new Object { foo: 42 }; + my q = new Dict { foo: 42 }; say(q.foo); . @@ -145,7 +142,7 @@ use _007::Test; outputs $program, qq[42\n], - "can create a Val::Object by explicitly naming 'Object'"; + "can create a Val::Dict by explicitly naming 'Dict'"; } { diff --git a/t/features/quasi.t b/t/features/quasi.t index 4a301939..081334b1 100644 --- a/t/features/quasi.t +++ b/t/features/quasi.t @@ -210,15 +210,14 @@ use _007::Test; say(type(quasi { none })); say(type(quasi { "James Bond" })); say(type(quasi { [0, 0, 7] })); - say(type(quasi { new Object { james: "Bond" } })); + say(type(quasi { { james: "Bond" } })); say(type(quasi { quasi { say("oh, james!") } })); say(type(quasi { (0 + 0 + 7) })); . outputs $program, \ + Term.Array Term.Dict Term.Quasi Infix>\ .map({ "\n" }).join, "quasi"; } @@ -233,10 +232,10 @@ use _007::Test; { my $program = q:to/./; - say(type(quasi { new Object { james: "Bond" } })); + say(type(quasi { { james: "Bond" } })); . - outputs $program, "\n", "quasi"; + outputs $program, "\n", "quasi"; } {