From b9229cc800d93aa924aa9b54fa069397c95ba828 Mon Sep 17 00:00:00 2001 From: larion_dev Date: Mon, 22 May 2017 16:57:41 +0700 Subject: [PATCH 1/5] Add Check --- mathics/builtin/inout.py | 123 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/mathics/builtin/inout.py b/mathics/builtin/inout.py index 1dd96a4b36..a1903be2d7 100644 --- a/mathics/builtin/inout.py +++ b/mathics/builtin/inout.py @@ -1191,6 +1191,129 @@ def check_message(expr): return True return False +class Check(Builtin): + """ +
+
'Check[$expr$, $failexpr$]' +
evaluates $expr$, and returns the result, unless messages were generated, in which case it evaluates and $failexpr$ will be returned. +
'Check[$expr$, $failexpr$, {s1::t1,s2::t2,…}]' +
checks only for the specified messages. +
+ + Return err when a message is generated: + >> Check[1/0, err] + : Infinite expression 1 / 0 encountered. + = err + + #> Check[1^0, err] + = 1 + + Check only for specific messages: + >> Check[Sin[0^0], err, Sin::argx] + : Indeterminate expression 0 ^ 0 encountered. + = Indeterminate + + >> Check[1/0, err, Power::infy] + : Infinite expression 1 / 0 encountered. + = err + + #> Check[1 + 2] + : Check called with 1 argument; 2 or more arguments are expected. + = Check[1 + 2] + + #> Check[1 + 2, err, 3 + 1] + : Message name 3 + 1 is not of the form symbol::name or symbol::name::language. + = Check[1 + 2, err, 3 + 1] + + #> Check[1 + 2, err, hello] + : Message name hello is not of the form symbol::name or symbol::name::language. + = Check[1 + 2, err, hello] + + #> Check[1/0, err, Compile::cpbool] + : Infinite expression 1 / 0 encountered. + = ComplexInfinity + + #> Check[{0^0, 1/0}, err] + : Indeterminate expression 0 ^ 0 encountered. + : Infinite expression 1 / 0 encountered. + = err + + #> Check[0^0/0, err, Power::indet] + : Indeterminate expression 0 ^ 0 encountered. + : Infinite expression 1 / 0 encountered. + = err + + #> Check[{0^0, 3/0}, err, Power::indet] + : Indeterminate expression 0 ^ 0 encountered. + : Infinite expression 1 / 0 encountered. + = err + + #> Check[1 + 2, err, {a::b, 2 + 5}] + : Message name 2 + 5 is not of the form symbol::name or symbol::name::language. + = Check[1 + 2, err, {a::b, 2 + 5}] + + #> Off[Power::infy] + #> Check[1 / 0, err] + = ComplexInfinity + + #> On[Power::infy] + #> Check[1 / 0, err] + : Infinite expression 1 / 0 encountered. + = err + """ + + attributes = ('HoldAll',) + + messages = { + 'argmu': 'Check called with 1 argument; 2 or more arguments are expected.', + 'name': 'Message name `1` is not of the form symbol::name or symbol::name::language.', + } + + def apply_1_argument(self, expr, evaluation): + 'Check[expr_]' + return evaluation.message('Check', 'argmu') + + def apply(self, expr, failexpr, params, evaluation): + 'Check[expr_, failexpr_, params___]' + + #Todo: To implement the third form of this function , we need to implement the function $MessageGroups first + #
'Check[$expr$, $failexpr$, "name"]' + #
checks only for messages in the named message group. + + def get_msg_list(exprs): + messages = [] + for expr in exprs: + if expr.has_form('List', None): + messages.extend(get_msg_list(expr.leaves)) + elif check_message(expr): + messages.append(expr) + else: + raise Exception(expr) + return messages + + check_messages = set(evaluation.get_quiet_messages()) + display_fail_expr = False + + params = params.get_sequence() + if len(params) == 0: + result = expr.evaluate(evaluation) + if(len(evaluation.out)): + display_fail_expr = True + else: + try: + msgs = get_msg_list(params) + for x in msgs: + check_messages.add(x) + except Exception as inst : + evaluation.message('Check', 'name', inst.args[0]) + return + result = expr.evaluate(evaluation) + for out_msg in evaluation.out: + pattern = Expression('MessageName', Symbol(out_msg.symbol), String(out_msg.tag)) + if pattern in check_messages: + display_fail_expr = True + break + return failexpr if display_fail_expr is True else result class Quiet(Builtin): """ From 3ac8ab8d3320741ca5f8e3371a263c8d08f9f793 Mon Sep 17 00:00:00 2001 From: larion_dev Date: Mon, 22 May 2017 16:59:54 +0700 Subject: [PATCH 2/5] Add Interrupt --- mathics/builtin/control.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mathics/builtin/control.py b/mathics/builtin/control.py index 0a9a8f88ef..582316c4f1 100644 --- a/mathics/builtin/control.py +++ b/mathics/builtin/control.py @@ -622,7 +622,22 @@ def apply(self, evaluation): raise AbortInterrupt +class Interrupt(Builtin): + """ +
+
'Interrupt[]' +
Interrupt an evaluation and returns '$Aborted'. +
+ >> Print["a"]; Interrupt[]; Print["b"] + | a + = $Aborted + """ + + def apply(self, evaluation): + 'Interrupt[]' + raise AbortInterrupt + class Return(Builtin): '''
From 34a945abb7377a7d6cedc06afc41e6d263aa5230 Mon Sep 17 00:00:00 2001 From: larion_dev Date: Mon, 22 May 2017 17:06:39 +0700 Subject: [PATCH 3/5] Add Unique --- mathics/builtin/scoping.py | 136 +++++++++++++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) diff --git a/mathics/builtin/scoping.py b/mathics/builtin/scoping.py index 8e3cfb34bb..996e20a2b9 100644 --- a/mathics/builtin/scoping.py +++ b/mathics/builtin/scoping.py @@ -206,6 +206,142 @@ def apply(self, vars, expr, evaluation): result = new_expr.evaluate(evaluation) return result +class Unique(Predefined): + """ +
+
'Unique[]' +
generates a new symbol and gives a name of the form '$number'. +
'Unique[x]' +
generates a new symbol and gives a name of the form 'x$number'. +
'Unique[{x, y, ...}]' +
generates a list of new symbols. +
'Unique["xxx"]' +
generates a new symbol and gives a name of the form 'xxxnumber'. +
+ + Create a unique symbol with no particular name: + >> Unique[] + = $1 + + >> Unique[sym] + = sym$1 + + Create a unique symbol whose name begins with x: + >> Unique["x"] + = x2 + + #> Unique[] + = $3 + + #> Unique[{}] + = {} + + #> Unique[{x, x}] + = {x$2, x$3} + + Each use of Unique[symbol] increments $ModuleNumber: + >> {$ModuleNumber, Unique[x], $ModuleNumber} + = {4, x$4, 5} + + Unique[symbol] creates symbols in the same way Module does: + >> {Module[{x}, x], Unique[x]} + = {x$5, x$6} + + Unique with more arguments + >> Unique[{x, "s"}, Flat ^ Listable ^ Orderless] + : Flat ^ Listable ^ Orderless is not a known attribute. + = Unique[{x, s}, Flat ^ Listable ^ Orderless] + + Unique call without symbol argument + >> Unique[x + y] + : x + y is not a symbol or a valid symbol name. + = Unique[x + y] + + #> Unique[1] + : 1 is not a symbol or a valid symbol name. + = Unique[1] + + #> Unique[{m, "s", n}, {Flat, Listable, Orderless}] + = {m$7, s4, n$8} + + #> Attributes[{m$7, s4, n$8}] + = {{Flat, Listable, Orderless}, {Flat, Listable, Orderless}, {Flat, Listable, Orderless}} + + #> Unique[{x, "s", 1}, {Flat ^ Listable ^ Orderless}] + : 1 is not a symbol or a valid symbol name. + = Unique[{x, s, 1}, {Flat ^ Listable ^ Orderless}] + + #> Unique[{"s"}, Flat] + = {s5} + + #> Attributes[s5] + = {Flat} + """ + + seq_number = 1 + + messages = { + 'usym': '`1` is not a symbol or a valid symbol name.', + 'argrx': 'Unique called with `1` arguments; 0 or 1 argument are expected.', + 'attnf': '`1` is not a known attribute.', + } + + attributes = ('Protected',) + + rules = { + 'Unique[x_Symbol]': 'Module[{x}, x]', + } + + def apply(self, evaluation): + 'Unique[]' + + new_name = '$%d' % (self.seq_number) + self.seq_number += 1 + return Symbol(new_name) + + def apply_symbol(self, vars, attributes, evaluation): + 'Unique[vars_, attributes___]' + + from mathics.core.parser import is_symbol_name + from mathics.builtin.attributes import get_symbol_list + + attributes = attributes.get_sequence() + if len(attributes) > 1: + return evaluation.message('Unique', 'argrx', Integer(len(attributes) + 1)) + + # Check valid symbol variables + symbols = vars.leaves if vars.has_form('List', None) else [vars] + for symbol in symbols: + if not isinstance(symbol, Symbol): + text = symbol.get_string_value() + if text is None or not is_symbol_name(text): + return evaluation.message('Unique', 'usym', symbol) + + # Check valid attributes + attrs = [] + if len(attributes) > 0: + attrs = get_symbol_list(attributes[0], lambda item: evaluation.message('Unique', 'attnf', item)) + if attrs is None: + return None + + # Generate list new symbols + list = [] + for symbol in symbols: + if isinstance(symbol, Symbol): + list.append(Module(Expression('List', symbol), symbol).evaluate(evaluation)) + else: + new_name = '%s%d' % (symbol.get_string_value(), self.seq_number) + self.seq_number += 1 + list.append(Symbol(new_name)) + + for symbol in list: + for att in attrs: + evaluation.definitions.set_attribute(symbol.get_name(), att) + + if vars.has_form('List', None): + return Expression('List', *list) + else: + return list[0] class Context(Builtin): r""" From 783f53b22545b949f22af67062299233c0ebe2ce Mon Sep 17 00:00:00 2001 From: larion_dev Date: Mon, 22 May 2017 17:31:03 +0700 Subject: [PATCH 4/5] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 04c71deb8b..283421649e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -49,7 +49,7 @@ before_install: - if [[ "$ALL_MODULES" == "true" ]]; then sudo apt-get update -qq && sudo apt-get install -qq python-enchant && - pip install numpy ipywidgets ipykernel IPython nltk langid pycountry pyenchant lxml matplotlib networkx && + pip install numpy ipywidgets ipykernel requests IPython==5.0.0 nltk langid pycountry pyenchant lxml matplotlib networkx && python travis.py && if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then pip install pattern; From 745a815bfb09f381f0ce36cb2ee6ea8a99d18d00 Mon Sep 17 00:00:00 2001 From: larion_dev Date: Tue, 6 Jun 2017 17:32:31 +0700 Subject: [PATCH 5/5] Update code for checking whether the symbol is defined or not --- mathics/builtin/scoping.py | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/mathics/builtin/scoping.py b/mathics/builtin/scoping.py index 996e20a2b9..22a0abf56b 100644 --- a/mathics/builtin/scoping.py +++ b/mathics/builtin/scoping.py @@ -229,9 +229,10 @@ class Unique(Predefined): Create a unique symbol whose name begins with x: >> Unique["x"] = x2 - + + #> $3 = 3; #> Unique[] - = $3 + = $4 #> Unique[{}] = {} @@ -262,9 +263,9 @@ class Unique(Predefined): = Unique[1] #> Unique[{m, "s", n}, {Flat, Listable, Orderless}] - = {m$7, s4, n$8} + = {m$7, s5, n$8} - #> Attributes[{m$7, s4, n$8}] + #> Attributes[{m$7, s5, n$8}] = {{Flat, Listable, Orderless}, {Flat, Listable, Orderless}, {Flat, Listable, Orderless}} #> Unique[{x, "s", 1}, {Flat ^ Listable ^ Orderless}] @@ -272,9 +273,9 @@ class Unique(Predefined): = Unique[{x, s, 1}, {Flat ^ Listable ^ Orderless}] #> Unique[{"s"}, Flat] - = {s5} + = {s6} - #> Attributes[s5] + #> Attributes[s6] = {Flat} """ @@ -297,6 +298,10 @@ def apply(self, evaluation): new_name = '$%d' % (self.seq_number) self.seq_number += 1 + #Next symbol in case of new name is defined before + while evaluation.definitions.get_definition(new_name, True) is not None: + new_name = '$%d' % (self.seq_number) + self.seq_number += 1 return Symbol(new_name) def apply_symbol(self, vars, attributes, evaluation): @@ -332,8 +337,11 @@ def apply_symbol(self, vars, attributes, evaluation): else: new_name = '%s%d' % (symbol.get_string_value(), self.seq_number) self.seq_number += 1 - list.append(Symbol(new_name)) - + # Next symbol in case of new name is defined before + while evaluation.definitions.get_definition(new_name, True) is not None: + new_name = '%s%d' % (symbol.get_string_value(), self.seq_number) + self.seq_number += 1 + list.append(Symbol(new_name)) for symbol in list: for att in attrs: evaluation.definitions.set_attribute(symbol.get_name(), att)