From 54ed1c0c3bb2f2b4fdbbdf43f014ff3cf483b91b Mon Sep 17 00:00:00 2001 From: Shin-ichi MORITA Date: Wed, 21 Feb 2024 06:55:13 +0900 Subject: [PATCH] Made values truthy or falsy. null and false are falsy, all the other values are truthy. --- doc/Literals.md | 2 ++ doc/TermExpressions.md | 16 +++++++++++++++- include/xemmai/ast.h | 7 ++++--- include/xemmai/boolean.h | 11 +++++++---- include/xemmai/class.h | 2 +- include/xemmai/fiber.h | 16 ---------------- include/xemmai/global.h | 9 ++------- include/xemmai/type.h | 6 +----- include/xemmai/value.h | 12 +++++++++++- src/ast.cc | 16 ++++++++++------ src/boolean.cc | 5 ----- src/code_operator.h | 4 +--- src/global.cc | 2 -- src/parser.cc | 6 ++---- src/type.cc | 36 +++++++++++++++++------------------- test/directory.xm | 2 +- test/operators.xm | 3 +-- test/pair.xm | 4 ++-- test/primitives.xm | 3 ++- test/psmtp.xm | 10 +++++----- test/ring.xm | 12 ++++++------ 21 files changed, 90 insertions(+), 94 deletions(-) diff --git a/doc/Literals.md b/doc/Literals.md index a464bfb4..4ba32589 100644 --- a/doc/Literals.md +++ b/doc/Literals.md @@ -16,6 +16,8 @@ This page explains literals. boolean: 'true' | 'false' ; +`null` and `false` are falsy. The other values are all truthy. + ## Integer Literals integer: digit+ ; diff --git a/doc/TermExpressions.md b/doc/TermExpressions.md index 8f857ed6..f2396eea 100644 --- a/doc/TermExpressions.md +++ b/doc/TermExpressions.md @@ -10,6 +10,8 @@ See [PrimaryExpressions](PrimaryExpressions.md). unary: ('+' | '-' | '!' | '~')* primary ; +Negate operator (`!`) returns `true` if the operand is falsy, returns `false` otherwise. + ## Multiplicative Expressions multiplicative: unary (('*' | '/' | '%') unary)* ; @@ -26,13 +28,21 @@ See [PrimaryExpressions](PrimaryExpressions.md). relational: shift (('<' | '>' | '<=' | '>=') shift)* ; +Relational, equality, and identity operators return either `true` or `false`. + ## Equality Expressions equality: relational (('==' | '!=') relational)* ; +## Identity Expressions + + identity: equality (('===' | '!==') equality)* ; + ## And Expressions - and: equality ('&' equality)* ; + and: identity ('&' identity)* ; + +Bitwise operators (`&`, `^`, and `|`) do bitwise operations if both the operands are integers, do boolean operations if both the operands are booleans, throws an exception otherwise. ## Xor Expressions @@ -46,10 +56,14 @@ See [PrimaryExpressions](PrimaryExpressions.md). and_also: or ('&&' or)* ; +Evaluates the left operand, returns it if it is falsy, evaluates the right operand and returns it otherwise. + ## Or Else Expressions or_else: and_also ('||' and_also)* ; +Evaluates the left operand, returns it if it is truthy, evaluates the right operand and returns it otherwise. + ## Conditional Expressions conditional: or_else ('?' conditional ':' conditional)? ; diff --git a/include/xemmai/ast.h b/include/xemmai/ast.h index d3787570..2a536ad3 100644 --- a/include/xemmai/ast.h +++ b/include/xemmai/ast.h @@ -163,6 +163,7 @@ struct t_lambda : t_node, t_scope struct t_if : t_node { std::unique_ptr v_condition; + bool v_preserve; std::vector> v_true; std::vector> v_false; t_block v_block_true; @@ -170,7 +171,7 @@ struct t_if : t_node t_block v_junction; t_block v_block_exit; - t_if(const t_at& a_at, std::unique_ptr&& a_condition) : t_node(a_at), v_condition(std::move(a_condition)) + t_if(const t_at& a_at, std::unique_ptr&& a_condition, bool a_preserve = false) : t_node(a_at), v_condition(std::move(a_condition)), v_preserve(a_preserve) { } virtual void f_flow(t_flow& a_flow); @@ -618,9 +619,9 @@ struct XEMMAI__LOCAL t_emit { v_code->v_ats.push_back({a_node->v_at, f_last()}); } - void f_emit_null() + t_emit& f_emit_null() { - (*this << e_instruction__NUL << v_stack).f_push(); + return (*this << e_instruction__NUL << v_stack).f_push(); } void f_emit_safe_point(ast::t_node* a_node) { diff --git a/include/xemmai/boolean.h b/include/xemmai/boolean.h index fe56c268..4b264837 100644 --- a/include/xemmai/boolean.h +++ b/include/xemmai/boolean.h @@ -1,7 +1,7 @@ #ifndef XEMMAI__BOOLEAN_H #define XEMMAI__BOOLEAN_H -#include "object.h" +#include "string.h" namespace xemmai { @@ -14,15 +14,18 @@ struct t_type_of : t_uninstantiatable> { static bool f_as(auto&& a_object) { - return a_object.f_boolean(); + return a_object && (a_object.f_tag() != e_tag__BOOLEAN || a_object.f_boolean()); } static bool f_is(t_object* a_object) { - return reinterpret_cast(a_object) == e_tag__BOOLEAN; + return true; } }; - XEMMAI__PUBLIC static t_object* f__string(bool a_self); + static t_object* f__string(bool a_self) + { + return t_string::f_instantiate(a_self ? L"true"sv : L"false"sv); + } static intptr_t f__hash(bool a_self) { return a_self ? 1 : 0; diff --git a/include/xemmai/class.h b/include/xemmai/class.h index 634199a8..1f549d31 100644 --- a/include/xemmai/class.h +++ b/include/xemmai/class.h @@ -15,7 +15,7 @@ struct t_type_of : t_uninstantiatable> f_finalize = f_do_scan; v_get = static_cast(&t_type_of::f_do_get); f_string = f_hash = f_not_supported0; - f_get_at = f_set_at = f_plus = f_minus = f_not = f_complement = f_multiply = f_divide = f_modulus = f_subtract = f_left_shift = f_right_shift = f_less = f_less_equal = f_greater = f_greater_equal = f_equals = f_not_equals = f_and = f_xor = f_or = f_not_supported1; + f_get_at = f_set_at = f_plus = f_minus = f_complement = f_multiply = f_divide = f_modulus = f_subtract = f_left_shift = f_right_shift = f_less = f_less_equal = f_greater = f_greater_equal = f_equals = f_not_equals = f_and = f_xor = f_or = f_not_supported1; } static void f_do_scan(t_object* a_this, t_scan a_scan); XEMMAI__PUBLIC t_pvalue f_do_get(t_object* a_this, t_object* a_key, size_t& a_index); diff --git a/include/xemmai/fiber.h b/include/xemmai/fiber.h index cbe62771..b3915da5 100644 --- a/include/xemmai/fiber.h +++ b/include/xemmai/fiber.h @@ -279,22 +279,6 @@ inline t_pvalue t_value::f_##a_name() const\ XEMMAI__VALUE__UNARY_ARITHMETIC(plus, ) XEMMAI__VALUE__UNARY_ARITHMETIC(minus, -) -template -inline t_pvalue t_value::f_not() const -{ - auto p = static_cast(*this); - switch (reinterpret_cast(p)) { - case e_tag__BOOLEAN: - return !v_boolean; - case e_tag__NULL: - case e_tag__INTEGER: - case e_tag__FLOAT: - f_throw(L"not supported."sv); - default: - XEMMAI__VALUE__UNARY(f_not) - } -} - template inline t_pvalue t_value::f_complement() const { diff --git a/include/xemmai/global.h b/include/xemmai/global.h index bfa313d3..026d5011 100644 --- a/include/xemmai/global.h +++ b/include/xemmai/global.h @@ -59,7 +59,6 @@ class t_global : public t_library t_slot v_symbol_set_at; t_slot v_symbol_plus; t_slot v_symbol_minus; - t_slot v_symbol_not; t_slot v_symbol_complement; t_slot v_symbol_multiply; t_slot v_symbol_divide; @@ -121,10 +120,6 @@ class t_global : public t_library { return v_symbol_minus; } - t_object* f_symbol_not() const - { - return v_symbol_not; - } t_object* f_symbol_complement() const { return v_symbol_complement; @@ -373,8 +368,8 @@ inline t_pvalue t_value::f_##a_name(const t_pvalue& a_value) const\ auto p = static_cast(*this);\ switch (reinterpret_cast(p)) {\ case e_tag__BOOLEAN:\ - f_check(a_value, L"argument0");\ - return static_cast(v_boolean a_operator f_as(a_value));\ + if (a_value.f_tag() != e_tag__BOOLEAN) [[unlikely]] f_throw_type_error(L"argument0");\ + return v_boolean a_operator a_value.v_boolean;\ case e_tag__INTEGER:\ f_check(a_value, L"argument0");\ return v_integer a_operator f_as(a_value);\ diff --git a/include/xemmai/type.h b/include/xemmai/type.h index 1df25d7e..d90bb376 100644 --- a/include/xemmai/type.h +++ b/include/xemmai/type.h @@ -109,7 +109,7 @@ struct t_type_of static XEMMAI__TYPE__IDS_MODIFIER std::array V_ids{f_type_id()}; static constexpr size_t V_native = 0; - static constexpr size_t V_fields = 26; + static constexpr size_t V_fields = 25; static t_pvalue f_transfer(auto* a_library, auto&& a_value) { @@ -230,8 +230,6 @@ struct t_type_of size_t (*f_plus)(t_object*, t_pvalue*) = f_do_plus; XEMMAI__PUBLIC static size_t f_do_minus(t_object* a_this, t_pvalue* a_stack); size_t (*f_minus)(t_object*, t_pvalue*) = f_do_minus; - XEMMAI__PUBLIC static size_t f_do_not(t_object* a_this, t_pvalue* a_stack); - size_t (*f_not)(t_object*, t_pvalue*) = f_do_not; XEMMAI__PUBLIC static size_t f_do_complement(t_object* a_this, t_pvalue* a_stack); size_t (*f_complement)(t_object*, t_pvalue*) = f_do_complement; XEMMAI__PUBLIC static size_t f_do_multiply(t_object* a_this, t_pvalue* a_stack); @@ -279,7 +277,6 @@ struct t_type_of if (T::f_do_set_at != U::f_do_set_at) f_set_at = T::f_do_set_at; if (T::f_do_plus != U::f_do_plus) f_plus = T::f_do_plus; if (T::f_do_minus != U::f_do_minus) f_minus = T::f_do_minus; - if (T::f_do_not != U::f_do_not) f_not = T::f_do_not; if (T::f_do_complement != U::f_do_complement) f_complement = T::f_do_complement; if (T::f_do_multiply != U::f_do_multiply) f_multiply = T::f_do_multiply; if (T::f_do_divide != U::f_do_divide) f_divide = T::f_do_divide; @@ -400,7 +397,6 @@ struct t_derived : T this->f_set_at = t_type::f_do_set_at; this->f_plus = t_type::f_do_plus; this->f_minus = t_type::f_do_minus; - this->f_not = t_type::f_do_not; this->f_complement = t_type::f_do_complement; this->f_multiply = t_type::f_do_multiply; this->f_divide = t_type::f_do_divide; diff --git a/include/xemmai/value.h b/include/xemmai/value.h index f3be3848..ba087d73 100644 --- a/include/xemmai/value.h +++ b/include/xemmai/value.h @@ -342,7 +342,17 @@ class t_value : public T_tag t_value f_set_at(const t_value& a_index, const t_value& a_value) const; t_value f_plus() const; t_value f_minus() const; - t_value f_not() const; + t_value f_not() const + { + switch (reinterpret_cast(f_tag())) { + case e_tag__NULL: + return true; + case e_tag__BOOLEAN: + return !v_boolean; + default: + return false; + } + } t_value f_complement() const; t_value f_multiply(const t_value& a_value) const; t_value f_divide(const t_value& a_value) const; diff --git a/src/ast.cc b/src/ast.cc index dcf0f64d..eb4110ad 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -9,12 +9,12 @@ namespace ast namespace { -void f_emit_block(t_emit& a_emit, const std::vector>& a_nodes, bool a_tail, bool a_clear) +void f_emit_block(t_emit& a_emit, const std::vector>& a_nodes, bool a_tail, bool a_clear, bool a_preserve = false) { auto i = a_nodes.begin(); auto j = a_nodes.end(); if (i == j) { - if (!a_clear) a_emit.f_emit_null(); + if (!a_clear) a_preserve ? a_emit.f_push() : a_emit.f_emit_null(); } else { for (--j; i != j; ++i) (*i)->f_emit(a_emit, false, false, true); (*i)->f_emit(a_emit, a_tail, false, a_clear); @@ -214,14 +214,14 @@ t_operand t_if::f_emit(t_emit& a_emit, bool a_tail, bool a_operand, bool a_clear a_emit << e_instruction__BRANCH << a_emit.v_stack << label0; auto privates = *a_emit.v_privates; auto stack = a_emit.v_stack; - f_emit_block(a_emit, v_true, a_tail, a_clear); + f_emit_block(a_emit, v_true, a_tail, a_clear, v_preserve); a_emit.f_join(v_junction); auto& label1 = a_emit.f_label(); a_emit << e_instruction__JUMP << label1; a_emit.f_target(label0); *a_emit.v_privates = privates; a_emit.v_stack = stack; - f_emit_block(a_emit, v_false, a_tail, a_clear); + f_emit_block(a_emit, v_false, a_tail, a_clear, v_preserve); a_emit.f_join(v_junction); a_emit.f_target(label1); a_emit.f_merge(v_junction); @@ -832,10 +832,12 @@ t_operand t_unary::f_emit(t_emit& a_emit, bool a_tail, bool a_operand, bool a_cl return t_literal(v_at, operand.v_integer).f_emit(a_emit, a_tail, a_operand, a_clear); case e_instruction__MINUS_T: return t_literal(v_at, -operand.v_integer).f_emit(a_emit, a_tail, a_operand, a_clear); + case e_instruction__NOT_T: + return t_literal(v_at, false).f_emit(a_emit, a_tail, a_operand, a_clear); case e_instruction__COMPLEMENT_T: return t_literal(v_at, ~operand.v_integer).f_emit(a_emit, a_tail, a_operand, a_clear); default: - f_throw(L"not supported."sv); + assert(false); } } else if (operand.v_tag == t_operand::e_tag__FLOAT) { a_emit.f_pop(); @@ -844,6 +846,8 @@ t_operand t_unary::f_emit(t_emit& a_emit, bool a_tail, bool a_operand, bool a_cl return t_literal(v_at, operand.v_float).f_emit(a_emit, a_tail, a_operand, a_clear); case e_instruction__MINUS_T: return t_literal(v_at, -operand.v_float).f_emit(a_emit, a_tail, a_operand, a_clear); + case e_instruction__NOT_T: + return t_literal(v_at, false).f_emit(a_emit, a_tail, a_operand, a_clear); default: f_throw(L"not supported."sv); } @@ -928,7 +932,7 @@ t_operand t_binary::f_emit(t_emit& a_emit, bool a_tail, bool a_operand, bool a_c case e_instruction__OR_TT: return t_literal(v_at, left.v_integer | right.v_integer).f_emit(a_emit, a_tail, a_operand, a_clear); default: - f_throw(L"not supported."sv); + assert(false); } } else if (right.v_tag == t_operand::e_tag__FLOAT) { a_emit.f_pop(); diff --git a/src/boolean.cc b/src/boolean.cc index 1f867dac..f57424ad 100644 --- a/src/boolean.cc +++ b/src/boolean.cc @@ -3,11 +3,6 @@ namespace xemmai { -t_object* t_type_of::f__string(bool a_self) -{ - return t_string::f_instantiate(a_self ? L"true"sv : L"false"sv); -} - void t_type_of::f_define() { t_define{f_global()} diff --git a/src/code_operator.h b/src/code_operator.h index 349c9a5f..597909dc 100644 --- a/src/code_operator.h +++ b/src/code_operator.h @@ -47,9 +47,7 @@ XEMMAI__CODE__UNARY_ARITHMETIC(PLUS, , f_plus) XEMMAI__CODE__UNARY_ARITHMETIC(MINUS, -, f_minus) XEMMAI__CODE__CASE_BEGIN(NOT) - if (a0.f_tag() == e_tag__BOOLEAN) { - XEMMAI__CODE__PRIMITIVE_CALL(!a0.v_boolean) - } else XEMMAI__CODE__OBJECT_OR_THROW(f_not) + XEMMAI__CODE__PRIMITIVE_CALL(!f_as(a0)) XEMMAI__CODE__CASE_END XEMMAI__CODE__CASE_BEGIN(COMPLEMENT) if (a0.f_tag() == e_tag__INTEGER) { diff --git a/src/global.cc b/src/global.cc index 7929c307..919a7906 100644 --- a/src/global.cc +++ b/src/global.cc @@ -43,7 +43,6 @@ void t_global::f_scan(t_scan a_scan) a_scan(v_symbol_set_at); a_scan(v_symbol_plus); a_scan(v_symbol_minus); - a_scan(v_symbol_not); a_scan(v_symbol_complement); a_scan(v_symbol_multiply); a_scan(v_symbol_divide); @@ -80,7 +79,6 @@ std::vector> t_global::f_define() v_symbol_set_at = t_symbol::f_instantiate(L"__set_at"sv); v_symbol_plus = t_symbol::f_instantiate(L"__plus"sv); v_symbol_minus = t_symbol::f_instantiate(L"__minus"sv); - v_symbol_not = t_symbol::f_instantiate(L"__not"sv); v_symbol_complement = t_symbol::f_instantiate(L"__complement"sv); v_symbol_multiply = t_symbol::f_instantiate(L"__multiply"sv); v_symbol_divide = t_symbol::f_instantiate(L"__divide"sv); diff --git a/src/parser.cc b/src/parser.cc index e189a192..8b8c70f6 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -594,9 +594,8 @@ std::unique_ptr t_parser::f_and_also(bool a_assignable) while (!v_lexer.f_newline() && v_lexer.f_token() == t_lexer::e_token__AND_ALSO) { t_at at = v_lexer.f_at(); v_lexer.f_next(); - auto branch = std::make_unique(at, std::move(node)); + auto branch = std::make_unique(at, std::move(node), true); branch->v_true.push_back(f_or(false)); - branch->v_false.emplace_back(new ast::t_literal(at, false)); node = std::move(branch); } return node; @@ -608,8 +607,7 @@ std::unique_ptr t_parser::f_or_else(bool a_assignable) while (!v_lexer.f_newline() && v_lexer.f_token() == t_lexer::e_token__OR_ELSE) { t_at at = v_lexer.f_at(); v_lexer.f_next(); - auto branch = std::make_unique(at, std::move(node)); - branch->v_true.emplace_back(new ast::t_literal(at, true)); + auto branch = std::make_unique(at, std::move(node), true); branch->v_false.push_back(f_and_also(false)); node = std::move(branch); } diff --git a/src/type.cc b/src/type.cc index f84ae782..a8c81f54 100644 --- a/src/type.cc +++ b/src/type.cc @@ -32,7 +32,6 @@ void t_type::f_define() (f_global()->f_symbol_set_at(), f_not_supported) (f_global()->f_symbol_plus(), f_not_supported) (f_global()->f_symbol_minus(), f_not_supported) - (f_global()->f_symbol_not(), f_not_supported) (f_global()->f_symbol_complement(), f_not_supported) (f_global()->f_symbol_multiply(), f_not_supported) (f_global()->f_symbol_divide(), f_not_supported) @@ -248,24 +247,23 @@ XEMMAI__TYPE__METHOD(get_at, 4, 1) XEMMAI__TYPE__METHOD(set_at, 5, 2) XEMMAI__TYPE__METHOD(plus, 6, 0) XEMMAI__TYPE__METHOD(minus, 7, 0) -XEMMAI__TYPE__METHOD(not, 8, 0) -XEMMAI__TYPE__METHOD(complement, 9, 0) -XEMMAI__TYPE__METHOD(multiply, 10, 1) -XEMMAI__TYPE__METHOD(divide, 11, 1) -XEMMAI__TYPE__METHOD(modulus, 12, 1) -XEMMAI__TYPE__METHOD(add, 13, 1) -XEMMAI__TYPE__METHOD(subtract, 14, 1) -XEMMAI__TYPE__METHOD(left_shift, 15, 1) -XEMMAI__TYPE__METHOD(right_shift, 16, 1) -XEMMAI__TYPE__METHOD(less, 17, 1) -XEMMAI__TYPE__METHOD(less_equal, 18, 1) -XEMMAI__TYPE__METHOD(greater, 19, 1) -XEMMAI__TYPE__METHOD(greater_equal, 20, 1) -XEMMAI__TYPE__METHOD(equals, 21, 1) -XEMMAI__TYPE__METHOD(not_equals, 22, 1) -XEMMAI__TYPE__METHOD(and, 23, 1) -XEMMAI__TYPE__METHOD(xor, 24, 1) -XEMMAI__TYPE__METHOD(or, 25, 1) +XEMMAI__TYPE__METHOD(complement, 8, 0) +XEMMAI__TYPE__METHOD(multiply, 9, 1) +XEMMAI__TYPE__METHOD(divide, 10, 1) +XEMMAI__TYPE__METHOD(modulus, 11, 1) +XEMMAI__TYPE__METHOD(add, 12, 1) +XEMMAI__TYPE__METHOD(subtract, 13, 1) +XEMMAI__TYPE__METHOD(left_shift, 14, 1) +XEMMAI__TYPE__METHOD(right_shift, 15, 1) +XEMMAI__TYPE__METHOD(less, 16, 1) +XEMMAI__TYPE__METHOD(less_equal, 17, 1) +XEMMAI__TYPE__METHOD(greater, 18, 1) +XEMMAI__TYPE__METHOD(greater_equal, 19, 1) +XEMMAI__TYPE__METHOD(equals, 20, 1) +XEMMAI__TYPE__METHOD(not_equals, 21, 1) +XEMMAI__TYPE__METHOD(and, 22, 1) +XEMMAI__TYPE__METHOD(xor, 23, 1) +XEMMAI__TYPE__METHOD(or, 24, 1) void f_throw_type_error [[noreturn]] (const std::type_info& a_type, const wchar_t* a_name) { diff --git a/test/directory.xm b/test/directory.xm index 3ccd5fd0..6c429c12 100644 --- a/test/directory.xm +++ b/test/directory.xm @@ -5,7 +5,7 @@ assert = @(x) x || throw Throwable("Assertion failed." directory = os.Directory("" + os.Path(system.script) / ".." try - while (entry = directory.read()) !== null + while entry = directory.read() special = entry.permissions >> 9 owner = entry.permissions >> 6 & 7 group = entry.permissions >> 3 & 7 diff --git a/test/operators.xm b/test/operators.xm index c1ea3493..13084713 100644 --- a/test/operators.xm +++ b/test/operators.xm @@ -6,7 +6,6 @@ Foo = Object + @ $__set_at = @(x, y) "a[" + x + "] = " + y $__plus = @ "+a" $__minus = @ "-a" - $__not = @ "!a" $__complement = @ "~a" $__multiply = @(x) "a * " + x $__divide = @(x) "a / " + x @@ -31,7 +30,7 @@ assert(a["x"] == "a[x]" assert((a["x"] = "y") == "a[x] = y" assert(+a == "+a" assert(-a == "-a" -assert(!a == "!a" +assert(!a === false assert(~a == "~a" assert(a * "x" == "a * x" assert(a / "x" == "a / x" diff --git a/test/pair.xm b/test/pair.xm index f6125212..2a2d8b95 100644 --- a/test/pair.xm +++ b/test/pair.xm @@ -4,12 +4,12 @@ Pair = Object + @ $__initialize = @(first, second) $first = first $second = second - $__string = @ $second === null ? $first.__string() : $first.__string() + " " + $second + $__string = @ $second ? $first.__string() + " " + $second : $first.__string() List = Object + @ $list $__initialize = @ $list = null - $__string = @ $list === null ? "()" : "(" + $list + ")" + $__string = @ $list ? "(" + $list + ")" : "()" $push = @(value) $list = Pair(value, $list $pop = @ value = $list.first diff --git a/test/primitives.xm b/test/primitives.xm index 39d39ea5..7f9a745a 100644 --- a/test/primitives.xm +++ b/test/primitives.xm @@ -125,7 +125,7 @@ foo = "foo" assert((false && foo) === false assert((true && foo) === foo assert((false || foo) === foo -assert((true || foo) === true +assert((foo || "bar") === foo print("+(0 + 1) = " + +(0 + 1) assert(+(0 + 1) == 1 @@ -219,6 +219,7 @@ assert(Bar(1.0).__equals(1.0) print("Bar(1.0).__equals(2.0) = " + Bar(1.0).__equals(2.0) assert(!Bar(1.0).__equals(2.0) +assert(!"" === false assert("" === "" assert("" + "" === "" assert(foo + "" === foo diff --git a/test/psmtp.xm b/test/psmtp.xm index 8bc87c28..cfa69b71 100644 --- a/test/psmtp.xm +++ b/test/psmtp.xm @@ -11,11 +11,11 @@ server = @(co, log) x = co("250 Hello " + hostname + "\n" continue if x.substring(0, 11) == "MAIL FROM: " - if sender === null + if sender + x = co("503 Sender already specified\n" + else sender = x.substring(11 x = co("250 Sender " + sender + "\n" - else - x = co("503 Sender already specified\n" continue if x.substring(0, 9) == "RCPT TO: " recipient = x.substring(9 @@ -23,12 +23,12 @@ server = @(co, log) x = co("250 Recipient " + recipient + "\n" continue if x == "DATA" - if sender === null + if !sender x = co("503 Sender not specified\n" else if recipients == "" x = co("503 Recipients not specified\n" else - mail = hostname === null ? "" : "\tReceived: from " + hostname + "\n" + mail = hostname ? "\tReceived: from " + hostname + "\n" : "" mail = mail + "\tFrom: " + sender + "\n" mail = mail + recipients mail = mail + "\t\n" diff --git a/test/ring.xm b/test/ring.xm index f65e3255..aba041e0 100644 --- a/test/ring.xm +++ b/test/ring.xm @@ -11,20 +11,20 @@ Ring = Object + @ $__initialize = @ $ring = null $__string = @ - if $ring === null - return "()" - else + if $ring return "(" + $string($ring.next) + ")" + else + return "()" $string = @(cell) cell === $ring && return cell.value.__string( return cell.value.__string() + " " + $string(cell.next) $push = @(value) cell = Cell(value - if $ring === null - cell.next = cell - else + if $ring cell.next = $ring.next $ring.next = cell + else + cell.next = cell $ring = cell $pop = @ cell = $ring.next