Skip to content

Commit 7a24deb

Browse files
committed
defined all functions
1 parent 4d3c59f commit 7a24deb

4 files changed

Lines changed: 74 additions & 20 deletions

File tree

Sources/Compiler/Environment.swift

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,6 @@ import OrderedCollections
1212
struct Environment {
1313
private var identifiers: OrderedDictionary<Substring, TypeContainer> = [:]
1414

15-
private var functions: OrderedDictionary<Substring, TypeScheme> = [
16-
"MAX": Builtins.max,
17-
"SUM": Builtins.sum,
18-
]
19-
2015
/// Holds the type in the map.
2116
struct TypeContainer {
2217
let type: Type
@@ -81,7 +76,7 @@ struct Environment {
8176

8277
subscript(function name: Substring, argCount argCount: Int) -> TypeScheme? {
8378
// TODO: Move this out of the env
84-
guard let scheme = self.functions[name],
79+
guard let scheme = Builtins.functions[name],
8580
case let .fn(params, ret) = scheme.type else { return nil }
8681

8782
// This is how variadics are handled. If a variadic function is called
@@ -120,7 +115,7 @@ struct Environment {
120115
.isNotDistinctFrom, .between, .and, .or, .isnull, .not:
121116
Builtins.comparison
122117
case .in: Builtins.in
123-
case .concat: Builtins.concat
118+
case .concat: Builtins.concatOp
124119
case .doubleArrow: Builtins.extract
125120
case .match: Builtins.match
126121
case .regexp: Builtins.regexp
@@ -132,7 +127,7 @@ struct Environment {
132127

133128
subscript(postfix op: Operator) -> TypeScheme? {
134129
return switch op {
135-
case .collate: Builtins.concat
130+
case .collate: Builtins.concatOp
136131
case .escape: Builtins.escape
137132
default: nil
138133
}

Sources/Compiler/Sema/Builtins.swift

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
// Created by Wes Wickwire on 3/3/25.
66
//
77

8+
import OrderedCollections
9+
810
enum Builtins {
911
/// Operators
1012
static let negate = TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .var(0)))
@@ -14,7 +16,7 @@ enum Builtins {
1416
static let arithmetic = TypeScheme(typeVariables: [0], type: .fn(params: [.var(0), .var(0)], ret: .var(0)))
1517
static let comparison = TypeScheme(typeVariables: [0], type: .fn(params: [.var(0), .var(0)], ret: .bool))
1618
static let `in` = TypeScheme(typeVariables: [0], type: .fn(params: [.var(0), .row(.unknown(.var(0)))], ret: .bool))
17-
static let concat = TypeScheme(typeVariables: [0, 1], type: .fn(params: [.var(0), .var(1)], ret: .text))
19+
static let concatOp = TypeScheme(typeVariables: [0, 1], type: .fn(params: [.var(0), .var(1)], ret: .text))
1820
static let extract = TypeScheme(typeVariables: [0, 1], type: .fn(params: [.var(0)], ret: .var(1)))
1921
static let extractJson = TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .any))
2022
static let collate = TypeScheme(typeVariables: [], type: .fn(params: [.text], ret: .text))
@@ -23,7 +25,56 @@ enum Builtins {
2325
static let regexp = TypeScheme(typeVariables: [], type: .fn(params: [.text, .text], ret: .bool))
2426
static let glob = TypeScheme(typeVariables: [], type: .fn(params: [.text, .text], ret: .bool))
2527

26-
/// Functions
27-
static let max = TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .var(0)), variadic: true)
28-
static let sum = TypeScheme(typeVariables: [TypeVariable(0, kind: .integer)], type: .fn(params: [.var(TypeVariable(0, kind: .integer))], ret: .var(TypeVariable(0, kind: .integer))))
28+
static let functions: OrderedDictionary<Substring, TypeScheme> = [
29+
// Scalar functions
30+
"abs": TypeScheme(typeVariables: [.integer(0)], type: .fn(params: [.var(.integer(0))], ret: .var(.integer(0)))),
31+
"changes": TypeScheme(typeVariables: [], type: .fn(params: [], ret: .integer)),
32+
"char": TypeScheme(typeVariables: [], type: .fn(params: [.integer], ret: .text), variadic: true),
33+
"coalesce": TypeScheme(typeVariables: [0], type: .fn(params: [.optional(.var(0))], ret: .var(0)), variadic: true),
34+
"concat": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .text)),
35+
"concat_ws": TypeScheme(typeVariables: [0], type: .fn(params: [.text, .var(0)], ret: .text)),
36+
"format": TypeScheme(typeVariables: [0], type: .fn(params: [.text, .var(0)], ret: .text)),
37+
"glob": Builtins.glob,
38+
"hex": TypeScheme(typeVariables: [], type: .fn(params: [.blob], ret: .text)),
39+
// iif - Cannot support currently since it takes its parameters in 2's
40+
"ifnull": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0), .var(1)], ret: .var(1))),
41+
"instr": TypeScheme(typeVariables: [], type: .fn(params: [.text, .text], ret: .integer)),
42+
"last_insert_rowid": TypeScheme(typeVariables: [], type: .fn(params: [], ret: .integer)),
43+
"length": TypeScheme(typeVariables: [], type: .fn(params: [.text], ret: .integer)),
44+
"like": TypeScheme(typeVariables: [], type: .fn(params: [.text, .text], ret: .bool)),
45+
"likelihood": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0), .real], ret: .var(0))),
46+
"likely": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .var(0))),
47+
"lower": TypeScheme(typeVariables: [], type: .fn(params: [.text], ret: .text)),
48+
"ltrim": TypeScheme(typeVariables: [], type: .fn(params: [.text, .text], ret: .text)),
49+
"max": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .var(0)), variadic: true),
50+
"min": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .var(0)), variadic: true),
51+
"nullif": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0), .var(0)], ret: .optional(.var(0)))),
52+
"octet_length": TypeScheme(typeVariables: [], type: .fn(params: [.text], ret: .integer)),
53+
"random": TypeScheme(typeVariables: [], type: .fn(params: [], ret: .integer)),
54+
"randomblob": TypeScheme(typeVariables: [], type: .fn(params: [.integer], ret: .blob)),
55+
"replace": TypeScheme(typeVariables: [], type: .fn(params: [.text, .text, .text], ret: .text)),
56+
"round": TypeScheme(typeVariables: [], type: .fn(params: [.real, .integer], ret: .real)),
57+
"rtrim": TypeScheme(typeVariables: [], type: .fn(params: [.text, .text], ret: .text)),
58+
"sign": TypeScheme(typeVariables: [.integer(0)], type: .fn(params: [.var(.integer(0))], ret: .integer)),
59+
"soundex": TypeScheme(typeVariables: [], type: .fn(params: [.text], ret: .text)),
60+
"substr": TypeScheme(typeVariables: [], type: .fn(params: [.text, .integer, .integer], ret: .text)),
61+
"substring": TypeScheme(typeVariables: [], type: .fn(params: [.text, .integer, .integer], ret: .text)),
62+
"trim": TypeScheme(typeVariables: [], type: .fn(params: [.text, .text], ret: .text)),
63+
"typeof": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .text)),
64+
"unhex": TypeScheme(typeVariables: [], type: .fn(params: [.text], ret: .blob)),
65+
"unicode": TypeScheme(typeVariables: [], type: .fn(params: [.text], ret: .integer)),
66+
"unlikely": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .var(0))),
67+
"upper": TypeScheme(typeVariables: [], type: .fn(params: [.text], ret: .text)),
68+
"zeroblob": TypeScheme(typeVariables: [], type: .fn(params: [.integer], ret: .blob)),
69+
70+
// Aggregate Functions
71+
"avg": TypeScheme(typeVariables: [.integer(0)], type: .fn(params: [.var(.integer(0))], ret: .var(.integer(0)))),
72+
"count": TypeScheme(typeVariables: [0], type: .fn(params: [.var(0)], ret: .integer)),
73+
"group_concat": TypeScheme(typeVariables: [], type: .fn(params: [.text, .text], ret: .text)),
74+
"string_agg": TypeScheme(typeVariables: [], type: .fn(params: [.text, .text], ret: .text)),
75+
// 'max' and 'min' are added through the scalar functions and can be reused.
76+
// In the future we may need to separate these if we store them separately
77+
"sum": TypeScheme(typeVariables: [.integer(0)], type: .fn(params: [.var(.integer(0))], ret: .var(.integer(0)))),
78+
"total": TypeScheme(typeVariables: [.integer(0)], type: .fn(params: [.var(.integer(0))], ret: .var(.integer(0)))),
79+
]
2980
}

Sources/Compiler/Sema/Type.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,4 +230,12 @@ public struct TypeVariable: Hashable, CustomStringConvertible, ExpressibleByInte
230230
func with(kind: Kind) -> TypeVariable {
231231
return TypeVariable(n, kind: kind)
232232
}
233+
234+
static func integer(_ n: Int) -> TypeVariable {
235+
return TypeVariable(n, kind: .integer)
236+
}
237+
238+
static func float(_ n: Int) -> TypeVariable {
239+
return TypeVariable(n, kind: .float)
240+
}
233241
}

Tests/CompilerTests/TypeCheckerTests.swift

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -97,20 +97,20 @@ class TypeCheckerTests: XCTestCase {
9797
}
9898

9999
func testTypeFunction() throws {
100-
try XCTAssertEqual(.integer, result(for: "MAX(1)").type)
101-
try XCTAssertEqual(.real, result(for: "MAX(1.0, 1)").type)
102-
try XCTAssertEqual(.real, result(for: "MAX(1, 1.0)").type)
103-
try XCTAssertEqual(.real, result(for: "MAX(1, 1, 1.0)").type)
104-
try XCTAssertEqual(.real, result(for: "MAX(1, 1, 1.0, 1)").type)
105-
try XCTAssertEqual(.real, result(for: "MAX(1, 1, 1, 1.0)").type)
100+
try XCTAssertEqual(.integer, result(for: "max(1)").type)
101+
try XCTAssertEqual(.real, result(for: "max(1.0, 1)").type)
102+
try XCTAssertEqual(.real, result(for: "max(1, 1.0)").type)
103+
try XCTAssertEqual(.real, result(for: "max(1, 1, 1.0)").type)
104+
try XCTAssertEqual(.real, result(for: "max(1, 1, 1.0, 1)").type)
105+
try XCTAssertEqual(.real, result(for: "max(1, 1, 1, 1.0)").type)
106106
}
107107

108108
func testTypeFunctionComplex() throws {
109109
let scope = try scope(table: "foo", schema: """
110110
CREATE TABLE foo(bar REAL NOT NULL);
111111
""")
112112

113-
let result = try result(for: "MAX(1, 1, bar + 1, 1)", in: scope)
113+
let result = try result(for: "max(1, 1, bar + 1, 1)", in: scope)
114114
XCTAssertEqual(.real, result.type)
115115
}
116116

@@ -119,7 +119,7 @@ class TypeCheckerTests: XCTestCase {
119119
CREATE TABLE foo(bar REAL NOT NULL);
120120
""")
121121

122-
let result = try result(for: "MAX(1, 1, bar + ?, 1)", in: scope)
122+
let result = try result(for: "max(1, 1, bar + ?, 1)", in: scope)
123123
XCTAssertEqual(.real, result.type)
124124
XCTAssertEqual(.real, type(for: 1, in: result))
125125
}

0 commit comments

Comments
 (0)