Skip to content

Commit 3b65304

Browse files
authored
Merge pull request #573 from dodona-edu/feat/add-types-typescript
Add types for typescript
2 parents 32f961a + d51c11e commit 3b65304

File tree

3 files changed

+118
-5
lines changed

3 files changed

+118
-5
lines changed

tested/languages/typescript/generators.py

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
from tested.datatypes import (
44
AdvancedNothingTypes,
55
AdvancedNumericTypes,
6+
AdvancedStringTypes,
7+
AllTypes,
68
BasicBooleanTypes,
79
BasicNothingTypes,
810
BasicNumericTypes,
911
BasicObjectTypes,
1012
BasicSequenceTypes,
1113
BasicStringTypes,
14+
resolve_to_basic,
1215
)
1316
from tested.datatypes.advanced import AdvancedObjectTypes
1417
from tested.languages.conventionalize import submission_file
@@ -33,6 +36,7 @@
3336
StringType,
3437
Value,
3538
VariableAssignment,
39+
VariableType,
3640
as_basic_type,
3741
)
3842
from tested.testsuite import MainInput
@@ -129,6 +133,74 @@ def convert_function_call(call: FunctionCall, internal=False) -> str:
129133
return result
130134

131135

136+
def convert_declaration(statement: Statement, tp: AllTypes | VariableType) -> str:
137+
if isinstance(tp, VariableType):
138+
return f"{tp.data}"
139+
elif tp == AdvancedNothingTypes.UNDEFINED:
140+
return "undefined"
141+
142+
basic = resolve_to_basic(tp)
143+
if basic == BasicBooleanTypes.BOOLEAN:
144+
return "boolean"
145+
elif basic == BasicStringTypes.TEXT:
146+
return "string"
147+
elif basic == BasicNumericTypes.INTEGER:
148+
return "number"
149+
elif basic == BasicNumericTypes.REAL:
150+
return "number"
151+
elif basic == BasicNothingTypes.NOTHING:
152+
return "null"
153+
elif basic == BasicObjectTypes.MAP:
154+
return "object"
155+
elif basic == BasicSequenceTypes.SEQUENCE:
156+
type_ = "Object"
157+
158+
if isinstance(statement, VariableAssignment):
159+
expression = statement.expression
160+
else:
161+
expression = statement
162+
if isinstance(expression, SequenceType):
163+
type_ = {
164+
(
165+
convert_declaration(element, element.type)
166+
if not isinstance(element, Identifier)
167+
and not isinstance(element, FunctionCall)
168+
else "id"
169+
)
170+
for element in expression.data
171+
}
172+
if "id" in type_:
173+
type_ = "any"
174+
else:
175+
type_ = "|".join(type_)
176+
177+
return f"Array<{type_}>"
178+
elif basic == BasicSequenceTypes.SET:
179+
type_ = "Object"
180+
181+
if isinstance(statement, VariableAssignment):
182+
expression = statement.expression
183+
else:
184+
expression = statement
185+
if isinstance(expression, SequenceType):
186+
type_ = {
187+
(
188+
convert_declaration(element, element.type)
189+
if not isinstance(element, Identifier)
190+
and not isinstance(element, FunctionCall)
191+
else "id"
192+
)
193+
for element in expression.data
194+
}
195+
if "id" in type_:
196+
type_ = "any"
197+
else:
198+
type_ = "|".join(type_)
199+
200+
return f"Set<{type_}>"
201+
raise AssertionError(f"Unknown type: {tp!r}")
202+
203+
132204
def convert_statement(statement: Statement, internal=False, full=False) -> str:
133205
if isinstance(statement, Identifier):
134206
return statement
@@ -143,11 +215,13 @@ def convert_statement(statement: Statement, internal=False, full=False) -> str:
143215
)
144216
elif isinstance(statement, VariableAssignment):
145217
if full:
146-
prefix = "let "
147-
else:
148-
prefix = ""
218+
return (
219+
f"let {statement.variable} : {convert_declaration(statement, statement.type)} = "
220+
f"{convert_statement(statement.expression, True)}"
221+
)
222+
149223
return (
150-
f"{prefix}{statement.variable} = "
224+
f"{statement.variable} = "
151225
f"{convert_statement(statement.expression, True)}"
152226
)
153227
raise AssertionError(f"Unknown statement: {statement!r}")

tests/test_language_quircks.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Tests for specific aspects of certain language implementations.
33
"""
44

5+
import itertools
56
import shutil
67
import sys
78
from pathlib import Path
@@ -10,8 +11,10 @@
1011

1112
from tested.configs import create_bundle
1213
from tested.datatypes import BasicBooleanTypes, BasicNumericTypes, BasicStringTypes
14+
from tested.dsl import parse_string
1315
from tested.languages.conventionalize import submission_name
1416
from tested.languages.generation import generate_statement
17+
from tested.languages.typescript.generators import convert_statement
1518
from tested.serialisation import (
1619
BooleanType,
1720
FunctionCall,
@@ -23,6 +26,42 @@
2326
from tests.manual_utils import assert_valid_output, configuration, execute_config
2427

2528

29+
def test_typescript_array_typing(tmp_path: Path, pytestconfig: pytest.Config):
30+
statement_string = "test = ['test', True, 10, 10.1, None, {'wow': 10}]"
31+
result = convert_statement(parse_string(statement_string), full=True)
32+
types = ["string", "boolean", "number", "object", "null"]
33+
permutations = list(itertools.permutations(types))
34+
valid_results = [
35+
f'let test : Array<{"|".join(perm)}> = ["test", true, 10, 10.1, null, new Map([["wow", 10]])]'
36+
for perm in permutations
37+
]
38+
39+
assert result in valid_results
40+
41+
42+
def test_typescript_set_typing(tmp_path: Path, pytestconfig: pytest.Config):
43+
statement_string = "test = {'test', True, 10, 10.1, None, {'wow': 10}}"
44+
result = convert_statement(parse_string(statement_string), full=True)
45+
types = ["string", "boolean", "number", "object", "null"]
46+
permutations = list(itertools.permutations(types))
47+
valid_results = [
48+
f'let test : Set<{"|".join(perm)}> = new Set(["test", true, 10, 10.1, null, new Map([["wow", 10]])])'
49+
for perm in permutations
50+
]
51+
52+
assert result in valid_results
53+
54+
55+
def test_typescript_function_call_typing(tmp_path: Path, pytestconfig: pytest.Config):
56+
statement_string = "test = {'test', True, testing(10)}"
57+
result = convert_statement(parse_string(statement_string), full=True)
58+
assert result == 'let test : Set<any> = new Set(["test", true, testing(10)])'
59+
60+
statement_string = "test = ['test', True, testing(10)]"
61+
result = convert_statement(parse_string(statement_string), full=True)
62+
assert result == 'let test : Array<any> = ["test", true, testing(10)]'
63+
64+
2665
def test_javascript_vanilla_object(tmp_path: Path, pytestconfig: pytest.Config):
2766
conf = configuration(
2867
pytestconfig,

tests/test_problem_statements.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ def test_template_natural_type_name_nl(lang: str, tested_type: Any, expected: st
161161
),
162162
(
163163
"typescript",
164-
"let random = new Random()\nrandom.newSequence(10, 10)\n[10, 5, 2, 8, 7, 1, 3, 4, 9, 6]",
164+
"let random : Random = new Random()\nrandom.newSequence(10, 10)\n[10, 5, 2, 8, 7, 1, 3, 4, 9, 6]",
165165
),
166166
],
167167
)

0 commit comments

Comments
 (0)