implement double
This commit is contained in:
@ -36,6 +36,8 @@ object inttrait:
|
|||||||
self $int_tobool
|
self $int_tobool
|
||||||
def tostr:
|
def tostr:
|
||||||
self $int_tostr
|
self $int_tostr
|
||||||
|
def todouble:
|
||||||
|
self $int_todouble
|
||||||
|
|
||||||
# Project: Boolean
|
# Project: Boolean
|
||||||
object booltrait:
|
object booltrait:
|
||||||
@ -50,6 +52,8 @@ object booltrait:
|
|||||||
self $bool_toint
|
self $bool_toint
|
||||||
def tostr:
|
def tostr:
|
||||||
self $bool_tostr
|
self $bool_tostr
|
||||||
|
def todouble:
|
||||||
|
self $bool_todouble
|
||||||
|
|
||||||
# Project: String
|
# Project: String
|
||||||
object strtrait:
|
object strtrait:
|
||||||
@ -66,3 +70,25 @@ object strtrait:
|
|||||||
self $str_tobool
|
self $str_tobool
|
||||||
def toint:
|
def toint:
|
||||||
self $str_toint
|
self $str_toint
|
||||||
|
def todouble:
|
||||||
|
self $str_todouble
|
||||||
|
|
||||||
|
# Project: Double
|
||||||
|
object doubletrait:
|
||||||
|
def eq(other):
|
||||||
|
self $double_eq(other)
|
||||||
|
def add(other):
|
||||||
|
self $double_add(other)
|
||||||
|
def sub(other):
|
||||||
|
self $double_sub(other)
|
||||||
|
def mul(other):
|
||||||
|
self $double_mul(other)
|
||||||
|
def div(other):
|
||||||
|
self $double_div(other)
|
||||||
|
|
||||||
|
def toint:
|
||||||
|
self $double_toint
|
||||||
|
def tobool:
|
||||||
|
self $double_tobool
|
||||||
|
def tostr:
|
||||||
|
self $double_tostr
|
||||||
|
@ -72,6 +72,10 @@ class Interpreter(object):
|
|||||||
value = bytecode.symbols[oparg]
|
value = bytecode.symbols[oparg]
|
||||||
w_value = self.space.newstring(value)
|
w_value = self.space.newstring(value)
|
||||||
stack.append(w_value)
|
stack.append(w_value)
|
||||||
|
elif opcode == compile.DOUBLE_LITERAL: # Project: Double
|
||||||
|
value = bytecode.symbols[oparg]
|
||||||
|
w_value = self.space.newdouble(value)
|
||||||
|
stack.append(w_value)
|
||||||
elif opcode == compile.MAKE_FUNCTION:
|
elif opcode == compile.MAKE_FUNCTION:
|
||||||
bc = bytecode.subbytecodes[oparg]
|
bc = bytecode.subbytecodes[oparg]
|
||||||
w_method = self.space.definemethod(name=bc.name, code=bc, w_target=w_context)
|
w_method = self.space.definemethod(name=bc.name, code=bc, w_target=w_context)
|
||||||
|
@ -112,6 +112,7 @@ import simpleast
|
|||||||
BOOL_LITERAL = 1 # 1 or 0 # Project: Boolean
|
BOOL_LITERAL = 1 # 1 or 0 # Project: Boolean
|
||||||
INT_LITERAL = 2 # integer value
|
INT_LITERAL = 2 # integer value
|
||||||
STRING_LITERAL = 3 # Project: String
|
STRING_LITERAL = 3 # Project: String
|
||||||
|
DOUBLE_LITERAL = 17 # Project: Double
|
||||||
ASSIGNMENT = 4 # index of attrname
|
ASSIGNMENT = 4 # index of attrname
|
||||||
METHOD_LOOKUP = 5 # index of method name
|
METHOD_LOOKUP = 5 # index of method name
|
||||||
METHOD_CALL = 6 # number of arguments
|
METHOD_CALL = 6 # number of arguments
|
||||||
@ -192,6 +193,7 @@ def compile(ast, argumentnames=[], name=None):
|
|||||||
stack_effects = {
|
stack_effects = {
|
||||||
BOOL_LITERAL: 1, # Project: Boolean
|
BOOL_LITERAL: 1, # Project: Boolean
|
||||||
STRING_LITERAL: 1, # Project: String
|
STRING_LITERAL: 1, # Project: String
|
||||||
|
DOUBLE_LITERAL: 1, # Project: Double
|
||||||
INT_LITERAL: 1,
|
INT_LITERAL: 1,
|
||||||
ASSIGNMENT: -1,
|
ASSIGNMENT: -1,
|
||||||
METHOD_LOOKUP: 1,
|
METHOD_LOOKUP: 1,
|
||||||
@ -295,6 +297,10 @@ class Compiler(object):
|
|||||||
def compile_StringLiteral(self, astnode, needsresult):
|
def compile_StringLiteral(self, astnode, needsresult):
|
||||||
self.emit(STRING_LITERAL, self.lookup_symbol(astnode.value)) # save string value to symboltable
|
self.emit(STRING_LITERAL, self.lookup_symbol(astnode.value)) # save string value to symboltable
|
||||||
|
|
||||||
|
# Project: Double
|
||||||
|
def compile_DoubleLiteral(self, astnode, needsresult):
|
||||||
|
self.emit(DOUBLE_LITERAL, self.lookup_symbol(astnode.value))
|
||||||
|
|
||||||
def compile_ImplicitSelf(self, astnode, needsresult):
|
def compile_ImplicitSelf(self, astnode, needsresult):
|
||||||
self.emit(IMPLICIT_SELF)
|
self.emit(IMPLICIT_SELF)
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ from c3computation import compute_C3_mro as c3
|
|||||||
|
|
||||||
|
|
||||||
class AbstractObject(object):
|
class AbstractObject(object):
|
||||||
|
|
||||||
def call(self, w_receiver, args_w):
|
def call(self, w_receiver, args_w):
|
||||||
return self
|
return self
|
||||||
|
|
||||||
@ -26,7 +25,6 @@ class AbstractObject(object):
|
|||||||
|
|
||||||
|
|
||||||
class W_NormalObject(AbstractObject):
|
class W_NormalObject(AbstractObject):
|
||||||
|
|
||||||
def __init__(self, name=None, slots=None, parents=None, space=None):
|
def __init__(self, name=None, slots=None, parents=None, space=None):
|
||||||
self.space = space
|
self.space = space
|
||||||
self.name = name
|
self.name = name
|
||||||
@ -131,12 +129,37 @@ class W_String(AbstractObject):
|
|||||||
|
|
||||||
__repr__ = __str__
|
__repr__ = __str__
|
||||||
|
|
||||||
|
def istrue(self):
|
||||||
|
return self.value != 0.
|
||||||
|
|
||||||
|
|
||||||
|
# Project: Double
|
||||||
|
class W_Double(W_NormalObject):
|
||||||
|
def __init__(self, value, space=None):
|
||||||
|
self.value = float(value)
|
||||||
|
self.space = space
|
||||||
|
self.__trait = "doubletrait"
|
||||||
|
|
||||||
|
def getparents(self):
|
||||||
|
if self.space is None:
|
||||||
|
return [] # for tests
|
||||||
|
trait = self.space.getbuiltin(self.__trait)
|
||||||
|
assert trait is not None, 'O_o bogus state'
|
||||||
|
return [trait]
|
||||||
|
|
||||||
|
def hasslot(self, name):
|
||||||
|
return False
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.value)
|
||||||
|
|
||||||
|
__repr__ = __str__
|
||||||
|
|
||||||
def istrue(self):
|
def istrue(self):
|
||||||
return self.value != ""
|
return self.value != ""
|
||||||
|
|
||||||
|
|
||||||
class W_Method(W_NormalObject):
|
class W_Method(W_NormalObject):
|
||||||
|
|
||||||
def __init__(self, code, *args, **kwargs):
|
def __init__(self, code, *args, **kwargs):
|
||||||
super(W_Method, self).__init__(*args, **kwargs)
|
super(W_Method, self).__init__(*args, **kwargs)
|
||||||
self.code = code
|
self.code = code
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from objmodel import W_Integer, W_Boolean, W_String
|
from objmodel import W_Integer, W_Boolean, W_String, W_Double
|
||||||
from objmodel import W_Method
|
from objmodel import W_Method
|
||||||
from objmodel import W_NormalObject
|
from objmodel import W_NormalObject
|
||||||
|
|
||||||
@ -57,6 +57,10 @@ class ObjectSpace(object):
|
|||||||
def newstring(self, value):
|
def newstring(self, value):
|
||||||
return W_String(value, space=self)
|
return W_String(value, space=self)
|
||||||
|
|
||||||
|
# Project: Double
|
||||||
|
def newdouble(self, value):
|
||||||
|
return W_Double(value, space=self)
|
||||||
|
|
||||||
def definemethod(self, name, code, w_target):
|
def definemethod(self, name, code, w_target):
|
||||||
w_meth = W_Method(code, name=name,
|
w_meth = W_Method(code, name=name,
|
||||||
slots={'__parent__': w_target},
|
slots={'__parent__': w_target},
|
||||||
|
@ -16,12 +16,10 @@ def primitive(name, unwrap_spec, wrap_spec): # decorator arguments
|
|||||||
|
|
||||||
unwrapped_args = ()
|
unwrapped_args = ()
|
||||||
for t, arg in zip(unwrap_spec, args): # unpack values from simple-objects
|
for t, arg in zip(unwrap_spec, args): # unpack values from simple-objects
|
||||||
if t is int:
|
if t in [int, str, float]: # Project: Double, String
|
||||||
unwrapped_args += (arg.value,)
|
unwrapped_args += (arg.value,)
|
||||||
elif t is bool: # Project: Boolean
|
elif t is bool: # Project: Boolean
|
||||||
unwrapped_args += (bool(arg.value),) # isn't really necessary because "1 or 0" is also valid
|
unwrapped_args += (bool(arg.value),) # isn't really necessary because "1 or 0" is also valid
|
||||||
elif t is str: # Project: String
|
|
||||||
unwrapped_args += (arg.value,)
|
|
||||||
else:
|
else:
|
||||||
unwrapped_args += (arg,)
|
unwrapped_args += (arg,)
|
||||||
|
|
||||||
@ -33,6 +31,8 @@ def primitive(name, unwrap_spec, wrap_spec): # decorator arguments
|
|||||||
return space.newbool(result)
|
return space.newbool(result)
|
||||||
elif wrap_spec is str: # Project: String
|
elif wrap_spec is str: # Project: String
|
||||||
return space.newstring(result)
|
return space.newstring(result)
|
||||||
|
elif wrap_spec is float: # Project: Double
|
||||||
|
return space.newdouble(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
unwrapper.__qualname__ = name
|
unwrapper.__qualname__ = name
|
||||||
@ -93,6 +93,11 @@ def simple_int_tobstr(a):
|
|||||||
return a
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("int_todouble", [int], float)
|
||||||
|
def simple_int_tobdouble(a):
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
# Project: Boolean
|
# Project: Boolean
|
||||||
@primitive("bool_and", [bool, bool], bool)
|
@primitive("bool_and", [bool, bool], bool)
|
||||||
def simple_bool_and(a, b):
|
def simple_bool_and(a, b):
|
||||||
@ -119,6 +124,11 @@ def simple_bool_tostr(a):
|
|||||||
return str(a).lower()
|
return str(a).lower()
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("bool_todouble", [bool], float)
|
||||||
|
def simple_bool_todouble(a):
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
# bool stuff for int
|
# bool stuff for int
|
||||||
@primitive("int_eq", [int, int], bool)
|
@primitive("int_eq", [int, int], bool)
|
||||||
def simple_int_eq(a, b):
|
def simple_int_eq(a, b):
|
||||||
@ -174,3 +184,49 @@ def simple_str_toint(a):
|
|||||||
@primitive("str_tobool", [str], bool)
|
@primitive("str_tobool", [str], bool)
|
||||||
def simple_str_tobool(a):
|
def simple_str_tobool(a):
|
||||||
return a == "true"
|
return a == "true"
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("str_todouble", [str], float)
|
||||||
|
def simple_str_todouble(a):
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
# Project: Double
|
||||||
|
@primitive("double_eq", [float, float], bool)
|
||||||
|
def simple_double_eq(a, b):
|
||||||
|
return a == b
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("double_add", [float, float], float)
|
||||||
|
def simple_double_add(a, b):
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("double_sub", [float, float], float)
|
||||||
|
def simple_double_sub(a, b):
|
||||||
|
return a - b
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("double_mul", [float, float], float)
|
||||||
|
def simple_double_mul(a, b):
|
||||||
|
return a * b
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("double_div", [float, float], float)
|
||||||
|
def simple_double_div(a, b):
|
||||||
|
return a / b
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("double_toint", [float], int)
|
||||||
|
def simple_double_toint(a):
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("double_tobool", [float], bool)
|
||||||
|
def simple_double_tobool(a):
|
||||||
|
return a
|
||||||
|
|
||||||
|
|
||||||
|
@primitive("double_tostr", [float], str)
|
||||||
|
def simple_double_tostr(a):
|
||||||
|
return a
|
||||||
|
@ -113,6 +113,16 @@ class StringLiteral(Expression):
|
|||||||
self.value = str(value)
|
self.value = str(value)
|
||||||
|
|
||||||
|
|
||||||
|
# Project: Double
|
||||||
|
class DoubleLiteral(Expression):
|
||||||
|
""" A double literal (like "1.0", ".0", "1.", "+1.0") """
|
||||||
|
|
||||||
|
attrs = ["value"]
|
||||||
|
|
||||||
|
def __init__(self, value):
|
||||||
|
self.value = float(value)
|
||||||
|
|
||||||
|
|
||||||
class MethodCall(Expression):
|
class MethodCall(Expression):
|
||||||
""" A call to a method with name 'methodname' on 'receiver' with
|
""" A call to a method with name 'methodname' on 'receiver' with
|
||||||
'arguments' (which is a list of expression ASTs).
|
'arguments' (which is a list of expression ASTs).
|
||||||
|
@ -158,11 +158,17 @@ OpenBracket = r'[\[\(\{]'
|
|||||||
CloseBracket = r'[\]\)\}]'
|
CloseBracket = r'[\]\)\}]'
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
# Project: Boolean, String
|
# Project: Boolean, String, Double
|
||||||
|
|
||||||
Boolean = group(r'true', r'false')
|
Boolean = r"true|false"
|
||||||
String = group(make_single_string(r"\'"), make_single_string(r'\"'))
|
String = group(make_single_string(r"\'"), make_single_string(r'\"'))
|
||||||
|
|
||||||
|
_sign = r"([+-])?"
|
||||||
|
_int = r"(([1-9][0-9]*)|0)"
|
||||||
|
_dec = r"(([0-9]*[1-9])|0)"
|
||||||
|
Double = group(_sign + group(_int, r"") + r"\." + _dec,
|
||||||
|
_sign + _int + r"\." + group(_dec, r""))
|
||||||
|
|
||||||
# ____________________________________________________________
|
# ____________________________________________________________
|
||||||
# Project: Sugar
|
# Project: Sugar
|
||||||
|
|
||||||
@ -182,8 +188,9 @@ While = r'while'
|
|||||||
Def = r'def'
|
Def = r'def'
|
||||||
Object = r'object'
|
Object = r'object'
|
||||||
|
|
||||||
tokens = ["If", "Else", "While", "Def", "Object", "Number", "Ignore",
|
tokens = ["If", "Else", "While", "Def", "Object", "Ignore",
|
||||||
"String", "Boolean", # Project: Boolean, String
|
"String", "Boolean", "Double", # Project: Boolean, String, Double
|
||||||
|
"Number", # after Double
|
||||||
"NewlineAndWhitespace", "OpenBracket", "CloseBracket", "Comma", "Assign", "Colon",
|
"NewlineAndWhitespace", "OpenBracket", "CloseBracket", "Comma", "Assign", "Colon",
|
||||||
"Increment", "Plus", "Minus", "Multiply", "Divide", "Modulo", # Project: Sugar
|
"Increment", "Plus", "Minus", "Multiply", "Divide", "Modulo", # Project: Sugar
|
||||||
"Name", "PrimitiveName"]
|
"Name", "PrimitiveName"]
|
||||||
|
@ -6,7 +6,7 @@ from simplelexer import lex
|
|||||||
import simpleast
|
import simpleast
|
||||||
|
|
||||||
pg = ParserGenerator(["If", "Else", "While", "Def", "Object", "Number",
|
pg = ParserGenerator(["If", "Else", "While", "Def", "Object", "Number",
|
||||||
"String", "Boolean", # Project: Boolean, String
|
"String", "Boolean", "Double", # Project: Boolean, String, Double
|
||||||
"Name", "Indent", "Dedent", "Newline", "OpenBracket",
|
"Name", "Indent", "Dedent", "Newline", "OpenBracket",
|
||||||
"CloseBracket", "Comma", "Assign", "Colon",
|
"CloseBracket", "Comma", "Assign", "Colon",
|
||||||
"Increment", "Plus", "Minus", "Multiply", "Divide", "Modulo", # Project: Sugar
|
"Increment", "Plus", "Minus", "Multiply", "Divide", "Modulo", # Project: Sugar
|
||||||
@ -210,6 +210,12 @@ def string_expression(stmt):
|
|||||||
return simpleast.StringLiteral(stmt[0].value[1:-1]) # cut off delimiters
|
return simpleast.StringLiteral(stmt[0].value[1:-1]) # cut off delimiters
|
||||||
|
|
||||||
|
|
||||||
|
# Project: Double
|
||||||
|
@pg.production("basic_expression : Double")
|
||||||
|
def double_expression(stmt):
|
||||||
|
return simpleast.DoubleLiteral(stmt[0].value)
|
||||||
|
|
||||||
|
|
||||||
@pg.production("basic_expression : implicitselfmethodcall")
|
@pg.production("basic_expression : implicitselfmethodcall")
|
||||||
def implicitselfmethodcall(call):
|
def implicitselfmethodcall(call):
|
||||||
methodcall = call[0]
|
methodcall = call[0]
|
||||||
|
@ -1,8 +1,26 @@
|
|||||||
|
from rply import Token
|
||||||
|
|
||||||
|
from simpleast import Program, ExprStatement, StringLiteral, ImplicitSelf, Assignment, DoubleLiteral
|
||||||
|
from simplelexer import lex
|
||||||
from simpleparser import parse
|
from simpleparser import parse
|
||||||
from objmodel import W_Integer
|
from objmodel import W_Integer, W_Double
|
||||||
from interpreter import Interpreter
|
from interpreter import Interpreter
|
||||||
|
|
||||||
|
|
||||||
|
def test_basic_double_lexing():
|
||||||
|
assert lex("0.1")[0] == Token("Double", "0.1")
|
||||||
|
assert lex(".1")[0] == Token("Double", ".1")
|
||||||
|
assert lex("1.")[0] == Token("Double", "1.")
|
||||||
|
assert lex("-5.5")[0] == Token("Double", "-5.5")
|
||||||
|
assert lex("-.5")[0] == Token("Double", "-.5")
|
||||||
|
assert lex("x = 0.0005")[:3] == [Token("Name", "x"), Token("Assign", "="), Token("Double", "0.0005")]
|
||||||
|
|
||||||
|
|
||||||
|
def test_basic_double_parsing():
|
||||||
|
assert parse("1.0") == Program([ExprStatement(DoubleLiteral("1.0"))])
|
||||||
|
assert parse("x = -.1") == Program([Assignment(ImplicitSelf(), "x", DoubleLiteral("-0.1"))])
|
||||||
|
|
||||||
|
|
||||||
def test_double_assignment():
|
def test_double_assignment():
|
||||||
ast = parse("""
|
ast = parse("""
|
||||||
x = 1.5
|
x = 1.5
|
||||||
@ -15,7 +33,25 @@ x = 1.5
|
|||||||
assert w_model.getvalue("x").value == 1.5
|
assert w_model.getvalue("x").value == 1.5
|
||||||
|
|
||||||
|
|
||||||
def test_double_operations():
|
def test_double_addition_subtraction():
|
||||||
|
ast = parse("""
|
||||||
|
x = 2.5 sub(2.4)
|
||||||
|
y = 2.5 add(2.4)
|
||||||
|
z = 3 sub(2.5)
|
||||||
|
""")
|
||||||
|
interpreter = Interpreter()
|
||||||
|
w_model = interpreter.make_module()
|
||||||
|
interpreter.eval(ast, w_model)
|
||||||
|
|
||||||
|
assert isinstance(w_model.getvalue("x"), W_Double)
|
||||||
|
assert w_model.getvalue("x").value == (2.5 - 2.4)
|
||||||
|
assert isinstance(w_model.getvalue("y"), W_Double)
|
||||||
|
assert w_model.getvalue("y").value == (2.5 + 2.4)
|
||||||
|
assert isinstance(w_model.getvalue("z"), W_Integer)
|
||||||
|
assert w_model.getvalue("z").value == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_double_division():
|
||||||
ast = parse("""
|
ast = parse("""
|
||||||
x = 3 div(2)
|
x = 3 div(2)
|
||||||
y = 3 div(2.0)
|
y = 3 div(2.0)
|
||||||
@ -33,6 +69,24 @@ z = 3.0 div(2.0)
|
|||||||
assert w_model.getvalue("z").value == 1.5
|
assert w_model.getvalue("z").value == 1.5
|
||||||
|
|
||||||
|
|
||||||
|
def test_double_multiplication():
|
||||||
|
ast = parse("""
|
||||||
|
x = 3.3 mul(3.0)
|
||||||
|
y = 3.3 mul(3)
|
||||||
|
z = 3 mul(3.3)
|
||||||
|
""")
|
||||||
|
interpreter = Interpreter()
|
||||||
|
w_model = interpreter.make_module()
|
||||||
|
interpreter.eval(ast, w_model)
|
||||||
|
|
||||||
|
assert isinstance(w_model.getvalue("x"), W_Double)
|
||||||
|
assert w_model.getvalue("x").value == (3.3 * 3.0)
|
||||||
|
assert isinstance(w_model.getvalue("y"), W_Double)
|
||||||
|
assert w_model.getvalue("y").value == (3.3 * 3)
|
||||||
|
assert isinstance(w_model.getvalue("z"), W_Integer)
|
||||||
|
assert w_model.getvalue("z").value == 9
|
||||||
|
|
||||||
|
|
||||||
def test_double_conversion():
|
def test_double_conversion():
|
||||||
ast = parse("""
|
ast = parse("""
|
||||||
x = 1.5 toint
|
x = 1.5 toint
|
||||||
|
Reference in New Issue
Block a user