Skip to content

Commit 1e09ff8

Browse files
committed
Merge branch 'add_dart_support'
2 parents 6a04908 + 1d2b0bb commit 1e09ff8

File tree

4 files changed

+220
-0
lines changed

4 files changed

+220
-0
lines changed
Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
# This script translates problems from the OpenAI HumanEval dataset into Dart.
2+
#
3+
# Note that for the Dart translation we reject Union types.
4+
5+
import re
6+
import ast
7+
from typing import List
8+
from base_language_translator import LanguageTranslator
9+
10+
DOCSTRING_LINESTART_RE = re.compile("""\n(\\s*)""")
11+
12+
needs_hashmap = False
13+
14+
def translate_type(t):
15+
global needs_hashmap
16+
match t:
17+
case ast.Subscript(ast.Name(id), slice, ctx):
18+
match id:
19+
case "List":
20+
if translate_type(slice) == "dynamic":
21+
return "List"
22+
else:
23+
return "List<" + translate_type(slice) + ">"
24+
case "Union":
25+
raise Exception("Union unsupported")
26+
case "Tuple":
27+
match slice:
28+
case ast.Tuple(elts, _ctx):
29+
tys = [translate_type(elem) for elem in elts]
30+
return "(" + ", ".join(tys) + ")"
31+
case other:
32+
raise Exception(f"Bad tuple: {slice}")
33+
case "Dict":
34+
match slice:
35+
case ast.Tuple([ast.Name(k), ast.Name(v)], _ctx):
36+
key, value = translate_type(k), translate_type(v)
37+
needs_hashmap = True
38+
return f"Map<{key}, {value}>"
39+
case other:
40+
raise Exception(f"Bad dict: {slice}")
41+
case "Optional":
42+
return translate_type(slice) + "?"
43+
case other:
44+
raise Exception(f"Bad generic {other}")
45+
case ast.Name("int") | "int":
46+
return "int"
47+
case ast.Name("float"):
48+
return "double"
49+
case ast.Name("bool"):
50+
return "bool"
51+
case ast.Name("str") | "str":
52+
return "String"
53+
case None:
54+
raise Exception("implicitly untyped argument")
55+
case ast.Name("Any"):
56+
return "dynamic"
57+
case ast.Name(x):
58+
raise Exception(f"unknown name {x}")
59+
case ast.Constant(Ellipsis):
60+
raise Exception("ellipsis unsupported")
61+
case _other:
62+
raise Exception(f"unknown annotation: {t}")
63+
64+
TargetExp = str
65+
66+
def coerce(expr: str, type) -> str:
67+
match expr, type:
68+
case _:
69+
return expr
70+
71+
class Translator:
72+
73+
stop = [ '\n}' ]
74+
75+
def __init__(self):
76+
global needs_hashmap
77+
self.type = None
78+
self.is_candidate_result = False
79+
80+
def file_ext(self):
81+
return "dart"
82+
83+
def translate_prompt(self, name: str, args: List[ast.arg], returns, description: str) -> str:
84+
global needs_hashmap
85+
description = "//" + re.sub(DOCSTRING_LINESTART_RE, "\n// ", description.strip()) + "\n"
86+
# Store this for later coercions on tests
87+
needs_hashmap = False
88+
self.type = [[arg.annotation for arg in args], returns]
89+
def translate_arg(arg):
90+
return translate_type(arg.annotation) + " " + arg.arg
91+
arg_strings = []
92+
return_type = ""
93+
try:
94+
arg_strings = [translate_arg(arg) for arg in args]
95+
return_type = translate_type(returns)
96+
except Exception as e:
97+
print(e)
98+
return None
99+
arg_list = ", ".join(arg_strings)
100+
return f"{description}{return_type} {name}({arg_list}) " + "{\n"
101+
102+
def test_suite_prefix_lines(self, entry_point) -> List[str]:
103+
"""
104+
This code goes at the start of the test suite.
105+
"""
106+
return [
107+
"void main() {",
108+
f" final candidate = {entry_point};",
109+
""
110+
]
111+
112+
def test_suite_suffix_lines(self) -> List[str]:
113+
return [
114+
"}",
115+
"",
116+
"void expect(dynamic a, dynamic b) {",
117+
" if (a == b) return;",
118+
"",
119+
" if (a is List && b is List) {",
120+
" expectList(a, b);",
121+
" } else if (a is Map && b is Map) {",
122+
" expectMap(a, b);",
123+
" } else {",
124+
" throw '$a != $b';",
125+
" }",
126+
"}",
127+
"",
128+
"void expectList(List a, List b) {",
129+
" if (a.length != b.length) throw 'list lengths are not equal';",
130+
"",
131+
" for (var i = 0; i < a.length; i++) {",
132+
" expect(a[i], b[i]);",
133+
" }",
134+
"}",
135+
"",
136+
"void expectMap(Map a, Map b) {",
137+
" if (a.length != b.length) throw 'map lengths are not equal';",
138+
"",
139+
" for (var key in a.keys) {",
140+
" expect(a[key], b[key]);",
141+
" }",
142+
"}",
143+
]
144+
145+
def deep_equality(self, left: str, right: str) -> str:
146+
"""
147+
All tests are assertions that compare deep equality between left and right.
148+
149+
Make sure you use the right equality operator for your language. For example,
150+
== is the wrong operator for Java and OCaml.
151+
"""
152+
if self.is_candidate_result:
153+
right = coerce(right, self.type[1])
154+
self.is_candidate_result = False
155+
return f" expect({left}, {right});"
156+
157+
def gen_literal(self, c: bool | str | int | float):
158+
"""Translate a literal expression
159+
c: is the literal value
160+
"""
161+
if type(c) == bool:
162+
return "true" if c else "false"
163+
elif type(c) == str:
164+
c = c.replace('\n','\\n')
165+
return f'"{c}"'
166+
elif c is None:
167+
return "null"
168+
return repr(c)
169+
170+
def gen_var(self, v: str) -> str:
171+
"""Translate a variable with name v."""
172+
return v
173+
174+
def gen_list(self, l: List[str]) -> str:
175+
return "[" + ", ".join(l) + "]"
176+
177+
def gen_tuple(self, t: List[str]) -> str:
178+
return "(" + ", ".join(t) + ")"
179+
180+
def gen_dict(self, keys: List[str], values: List[str]) -> str:
181+
return "{" + ", ".join(f"{k}: {v}" for k, v in zip(keys, values)) + "}"
182+
183+
def gen_call(self, func: str, args: List[str]) -> str:
184+
"""Translate a function call `func(args)`
185+
A function call f(x, y, z) translates to f(x, y, z)
186+
"""
187+
if func == "candidate":
188+
self.is_candidate_result = True
189+
args = [coerce(arg, self.type[0][i]) for i, arg in enumerate(args)]
190+
return f"{func}(" + ", ".join(args) + ")"

dataset_builder/terms.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ OCaml,ml,list,list,tuple,association list,None,true,false
2424
Matlab,m,array,array,array,dictionary,<missing>,true,false
2525
Haskell,hs,list,list,tuple,association list,Nothing,True,False
2626
Clojure,clj,vector,list,vector,map,nil,true,false
27+
Dart,dart,list,list,record,map,null,true,false

evaluation/src/containerized_eval.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import eval_clj
2828
import eval_v
2929
import eval_lean
30+
import eval_dart
3031
import tempfile
3132

3233

@@ -61,6 +62,7 @@
6162
"clj": (eval_clj.eval_script, ".clj"),
6263
"coq": (eval_v.eval_script, ".v"),
6364
"lean": (eval_lean.eval_script, ".lean"),
65+
"dart": (eval_dart.eval_script, ".dart"),
6466
}
6567

6668
def eval_string_script(language, program):

evaluation/src/eval_dart.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from pathlib import Path
2+
from safe_subprocess import run
3+
4+
5+
def eval_script(path: Path):
6+
r = run(["dart", "analyze", "--no-fatal-warnings", str(path)], timeout_seconds=15)
7+
if r.exit_code != 0:
8+
return {
9+
"status": "SyntaxError",
10+
"exit_code": r.exit_code,
11+
"stdout": r.stdout,
12+
"stderr": r.stderr,
13+
}
14+
15+
r = run(["dart", str(path)], timeout_seconds=15)
16+
if r.timeout:
17+
status = "Timeout"
18+
elif r.exit_code == 0:
19+
status = "OK"
20+
else:
21+
status = "Exception"
22+
return {
23+
"status": status,
24+
"exit_code": r.exit_code,
25+
"stdout": r.stdout,
26+
"stderr": r.stderr,
27+
}

0 commit comments

Comments
 (0)