From 312f10ce338517b46ea61e99c65d6aac8a7a822e Mon Sep 17 00:00:00 2001 From: Cat Stevens Date: Tue, 19 Feb 2019 02:05:06 -0500 Subject: [PATCH] =?UTF-8?q?Deprecate=20`Object.:`;=20add=20=EF=BC=9A,=20?= =?UTF-8?q?=C2=A6=20and=20=E2=AB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deprecate the `:` (colon) method from Object. Starting with Sidef v4.0 it will be removed from Object entirely, and only be used to create Complex and standard named param- eter syntax for Blocks (when its LHS is a bareword). The utility of `:` has been bisected into the `:` (fat/fullwidth colon; more easily written `¦`) and `⫶` (triple colon). `:` as a Pair constructor remains for now, but code using it should be updated to use the new methods. - Object.:, the fullwidth colon U+FF1A: force creation of a Pair from self and the first argument. - Object.¦, the broken bar U+A6: alias for `:` with a shorter hex value to type when using Unicode input methods. - ⫶, the triple-colon operator U+2AF6: force creation of a NamedParam with the object on its LHS as the name. Whereas the normal NamedParam colon operator `a: val` expects a bareword on its LHS, the triple-colon evaluates its left hand side and therefore allows any value from a names or expressions as the name in a NamedParam. Previously, it wasn't possible to generate NamedParams without `eval` because of the bareword restriction. #Previously it was not possible to iterate an #array of strings and generate NamedParams #from them, because the : (colon) NamedParam #operator (understandably) doesn't even accept #a parenthesised expression on its LHS. --- MANIFEST | 1 + lib/Sidef/Object/Object.pm | 17 +++++++++++++- lib/Sidef/Parser.pm | 6 ++++- scripts/Tests/hash_concat.sf | 2 +- scripts/Tests/pair_namedparam_force_ops.sf | 18 +++++++++++++++ scripts/Tests/pairs_test.sf | 2 +- scripts/Tests/roman_numerals_decoding.sf | 2 +- scripts/Tests/roman_numerals_decoding_3.sf | 26 +++++++++++----------- scripts/Tests/roman_numerals_encoding.sf | 2 +- scripts/Tests/roman_numerals_encoding_2.sf | 8 +++---- 10 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 scripts/Tests/pair_namedparam_force_ops.sf diff --git a/MANIFEST b/MANIFEST index e2f98790e..1fd641c7f 100644 --- a/MANIFEST +++ b/MANIFEST @@ -848,6 +848,7 @@ scripts/Tests/objects_init.sf scripts/Tests/one-dimensional_cellular_automata.sf scripts/Tests/one-dimensional_cellular_automata_2.sf scripts/Tests/open.sf +scripts/Tests/pair_namedparam_force_ops.sf scripts/Tests/pairs_test.sf scripts/Tests/palindrome_recursive.sf scripts/Tests/pascal_matrix_generation.sf diff --git a/lib/Sidef/Object/Object.pm b/lib/Sidef/Object/Object.pm index 2b3ba431d..2f69a3ed2 100644 --- a/lib/Sidef/Object/Object.pm +++ b/lib/Sidef/Object/Object.pm @@ -367,11 +367,26 @@ package Sidef::Object::Object { $func->call($arg, @args); }; - # Pair operator + # Deprecated pair method: ASCII colon; U+3A *{__PACKAGE__ . '::' . ':'} = sub { Sidef::Types::Array::Pair->new($_[0], $_[1]); }; + # TODO: v4.0: the following 2 methods should create an Array with 2 elements + # Pair (2-Array) method: Fullwidth Colon; U+FF1A + *{__PACKAGE__ . '::' . ':'} = sub { + Sidef::Types::Array::Pair->new($_[0], $_[1]); + }; + + # Pair (2-Array) method: Broken bar; U+A6 + # Easier to type than U+FF1A, but uglier + *{__PACKAGE__ . '::' . '¦'} = \&{__PACKAGE__ . '::' . ':'}; + + # NamedParam method: Triple Colon Operator; U+2AF6 + *{__PACKAGE__ . '::' . '⫶'} = sub { + Sidef::Variable::NamedParam->new($_[0], $_[1]); + }; + # Logical AND *{__PACKAGE__ . '::' . '&&'} = sub { $_[0] ? $_[1] : $_[0]; diff --git a/lib/Sidef/Parser.pm b/lib/Sidef/Parser.pm index 7f423ddd9..d1b06f1a5 100644 --- a/lib/Sidef/Parser.pm +++ b/lib/Sidef/Parser.pm @@ -324,7 +324,9 @@ package Sidef::Parser { ... != .. \\\\= \\\\ - !! ! : « » ~ + !! ! + : : ⫶ ¦ + « » ~ ); qr{ @@ -1149,6 +1151,8 @@ package Sidef::Parser { return Sidef::Types::String::String->new($1); } + # Bareword followed by a colon becomes a NamedParam with the bareword + # on the LHS if (/\G([^\W\d]\w*+):(?![=:])/gc) { my $name = $1; my $obj = $self->parse_obj(code => $opt{code}); diff --git a/scripts/Tests/hash_concat.sf b/scripts/Tests/hash_concat.sf index abe55d4c3..6b1b30129 100644 --- a/scripts/Tests/hash_concat.sf +++ b/scripts/Tests/hash_concat.sf @@ -14,7 +14,7 @@ assert_eq(hash{:a}, :b) hash += %w(c d) # 2-item array assert_eq(hash{:c}, :d) -hash += "2":3 # an actual Pair +hash += "2":3 # an actual Pair assert_eq(hash{"2"}, 3) say "** Test passed!" diff --git a/scripts/Tests/pair_namedparam_force_ops.sf b/scripts/Tests/pair_namedparam_force_ops.sf new file mode 100644 index 000000000..cedad0bca --- /dev/null +++ b/scripts/Tests/pair_namedparam_force_ops.sf @@ -0,0 +1,18 @@ +#! /usr/bin/ruby + +var f = :name +assert_eq(f⫶ 1 -> dump, name: 1 -> dump) +assert_eq(f⫶ 1 -> dump, (f)⫶ 1 -> dump) +assert_eq((f)⫶ 1 -> dump, name: 1 -> dump) +assert_eq(:a⫶ 1 -> dump, a:1 -> dump) + +var n = 1 + +assert_ne(n: 2 -> dump, (n): 2 -> dump) +assert_eq((n): 2 -> dump, 1: 2 -> dump) +assert_eq(n:2, Pair(1, 2)) +assert_eq(1:2, 1+2i) +assert_eq(1: 2, Pair(1, 2)) +assert_eq(1¦ 2, Pair(1, 2)) + +say "** Test passed!" diff --git a/scripts/Tests/pairs_test.sf b/scripts/Tests/pairs_test.sf index cee19b73d..40f29350c 100644 --- a/scripts/Tests/pairs_test.sf +++ b/scripts/Tests/pairs_test.sf @@ -4,7 +4,7 @@ ## This script is used for testing only # -var tree = 'root':'child':'grandchild':'end'; +var tree = 'root':'child':'grandchild':'end'; while (true) { say tree.first; diff --git a/scripts/Tests/roman_numerals_decoding.sf b/scripts/Tests/roman_numerals_decoding.sf index 365a2b214..94cbf863e 100644 --- a/scripts/Tests/roman_numerals_decoding.sf +++ b/scripts/Tests/roman_numerals_decoding.sf @@ -29,7 +29,7 @@ func roman2arabic (roman) { ## MAIN # -['MCMXC':1990, 'MMVIII':2008, 'MDCLXVI':1666].each { |pair| +[:MCMXC:1990, :MMVIII:2008, :MDCLXVI:1666].each { |pair| var arabic = roman2arabic(pair.first) == pair.second || die "Error occurred on #{pair.first}\n"; diff --git a/scripts/Tests/roman_numerals_decoding_3.sf b/scripts/Tests/roman_numerals_decoding_3.sf index 667449e14..dd6082bb5 100644 --- a/scripts/Tests/roman_numerals_decoding_3.sf +++ b/scripts/Tests/roman_numerals_decoding_3.sf @@ -2,19 +2,19 @@ func roman2arabic(digit) { digit.uc.trans([ - 'M': '1000+', - 'CM': '900+', - 'D': '500+', - 'CD': '400+', - 'C': '100+', - 'XC': '90+', - 'L': '50+', - 'XL': '40+', - 'X': '10+', - 'IX': '9+', - 'V': '5+', - 'IV': '4+', - 'I': '1+', + 'M': '1000+', + 'CM': '900+', + 'D': '500+', + 'CD': '400+', + 'C': '100+', + 'XC': '90+', + 'L': '50+', + 'XL': '40+', + 'X': '10+', + 'IX': '9+', + 'V': '5+', + 'IV': '4+', + 'I': '1+', ]).split('+').map{.to_i}.sum; } diff --git a/scripts/Tests/roman_numerals_encoding.sf b/scripts/Tests/roman_numerals_encoding.sf index 125c752a5..fcc0d2a8e 100644 --- a/scripts/Tests/roman_numerals_encoding.sf +++ b/scripts/Tests/roman_numerals_encoding.sf @@ -36,7 +36,7 @@ func arabic2roman (num) { ## MAIN # -[[1990,'MCMXC'], [2008,'MMVIII'], [1666,'MDCLXVI']].each { |pair| +[1990::MCMXC, 2008::MMVIII, 1666::MDCLXVI].each { |pair| var roman = arabic2roman(pair[0]); roman == pair[1] || "Error occurred on number: #{pair[0]}\n".die; "%s in roman is %s".printlnf(pair[0], roman); diff --git a/scripts/Tests/roman_numerals_encoding_2.sf b/scripts/Tests/roman_numerals_encoding_2.sf index ed1ec33e0..b348eae48 100644 --- a/scripts/Tests/roman_numerals_encoding_2.sf +++ b/scripts/Tests/roman_numerals_encoding_2.sf @@ -5,10 +5,10 @@ func arabic2roman(num, roman='') { static lookup = [ - :M:1000, :CM:900, :D:500, - :CD:400, :C:100, :XC:90, - :L:50, :XL:40, :X:10, - :IX:9, :V:5, :IV:4, :I:1 + :M:1000, :CM:900, :D:500, + :CD:400, :C:100, :XC:90, + :L:50, :XL:40, :X:10, + :IX:9, :V:5, :IV:4, :I:1 ]; lookup.each { |pair|