firefly-compiler 0.6.21 → 0.6.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.vscode/settings.json +1 -1
- package/compiler/Inference.ff +17 -1
- package/compiler/LspHook.ff +15 -5
- package/core/Ordering.ff +1 -1
- package/experimental/inceptron/Run.ff +47 -0
- package/experimental/mattis/Tree.ff +44 -0
- package/experimental/tests/TestListOrdering.ff +7 -0
- package/experimental/tests/TestOrder.ff +4 -0
- package/experimental/tests/TestSql.ff +18 -0
- package/lsp/.firefly/package.ff +1 -0
- package/lsp/CompletionHandler.ff +112 -6
- package/lsp/Handler.ff +205 -7
- package/lsp/LanguageServer.ff +5 -0
- package/lsp/SemanticTokenTypes.ff +62 -0
- package/lsp/Sql.ff +1395 -0
- package/lsp/SqlStatement.ff +34 -0
- package/lsp/SqlSuggestion.ff +295 -0
- package/output/js/ff/compiler/Builder.mjs +2 -2
- package/output/js/ff/compiler/Builder.mjs.map +1 -1
- package/output/js/ff/compiler/Dependencies.mjs +2 -2
- package/output/js/ff/compiler/Dependencies.mjs.map +1 -1
- package/output/js/ff/compiler/Inference.mjs +36 -16
- package/output/js/ff/compiler/Inference.mjs.map +4 -2
- package/output/js/ff/compiler/LspHook.mjs +10 -10
- package/output/js/ff/compiler/LspHook.mjs.map +4 -3
- package/output/js/ff/compiler/Main.mjs +4 -4
- package/output/js/ff/compiler/Main.mjs.map +1 -1
- package/output/js/ff/core/Ordering.mjs +2 -2
- package/output/js/ff/core/Ordering.mjs.map +1 -1
- package/package.json +1 -1
- package/postgresql/Pg.ff +49 -26
- package/vscode/client/src/extension.ts +5 -0
- package/vscode/package.json +7 -1
package/.vscode/settings.json
CHANGED
package/compiler/Inference.ff
CHANGED
|
@@ -819,12 +819,28 @@ extend self: Inference {
|
|
|
819
819
|
self.unification.unify(term.at, selfParameter.valueType, recordType)
|
|
820
820
|
let arguments = self.inferArguments(term.at, name, environment, signature.parameters.dropFirst(), e.arguments)
|
|
821
821
|
self.unification.affect(term.at, signature.effect, environment.effect)
|
|
822
|
-
e.ECall(
|
|
822
|
+
let result = e.ECall(
|
|
823
823
|
target = StaticCall(name, instanceCall = False, tailCall = tailCall)
|
|
824
824
|
typeArguments = instantiation.map {_.second}
|
|
825
825
|
arguments = [selfArgument, ...arguments]
|
|
826
826
|
effect = signature.effect
|
|
827
827
|
)
|
|
828
|
+
if(self.lspHook.sql) {
|
|
829
|
+
if(name == "ff:postgresql/Pg.PgConnection_statement") {
|
|
830
|
+
self.lspHook.sqlStrings.push(result)
|
|
831
|
+
} elseIf {name == "ff:postgresql/Pg.PgStatement_map"} {
|
|
832
|
+
self.lspHook.sqlStrings.push(result)
|
|
833
|
+
} elseIf {name == "ff:postgresql/Pg.PgStatement_each"} {
|
|
834
|
+
self.lspHook.sqlStrings.push(result)
|
|
835
|
+
} elseIf {name == "ff:postgresql/Pg.PgStatement_any"} {
|
|
836
|
+
self.lspHook.sqlStrings.push(result)
|
|
837
|
+
} elseIf {name == "ff:postgresql/Pg.PgStatement_all"} {
|
|
838
|
+
self.lspHook.sqlStrings.push(result)
|
|
839
|
+
} elseIf {name == "ff:postgresql/Pg.PgStatement_run"} {
|
|
840
|
+
self.lspHook.sqlStrings.push(result)
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
result
|
|
828
844
|
| _ => fail(term.at, "Call expected")
|
|
829
845
|
}
|
|
830
846
|
}
|
package/compiler/LspHook.ff
CHANGED
|
@@ -8,19 +8,29 @@ class LspHook(
|
|
|
8
8
|
insertIdentifier: Bool
|
|
9
9
|
trackSymbols: Bool
|
|
10
10
|
arrayOfResults: Array[ResultHook]
|
|
11
|
+
sql: Bool
|
|
12
|
+
sqlStrings: Array[Term]
|
|
11
13
|
)
|
|
12
14
|
|
|
13
|
-
disabled(): LspHook {
|
|
14
|
-
new(None, None, False, False)
|
|
15
|
+
disabled(sql: Bool = False): LspHook {
|
|
16
|
+
new(None, None, False, False, sql)
|
|
15
17
|
}
|
|
16
18
|
|
|
17
|
-
new(
|
|
19
|
+
new(
|
|
20
|
+
at: Option[Location]
|
|
21
|
+
definedAt: Option[Location]
|
|
22
|
+
insertIdentifier: Bool
|
|
23
|
+
trackSymbols: Bool
|
|
24
|
+
sql: Bool = False
|
|
25
|
+
): LspHook {
|
|
18
26
|
LspHook( // Default dummy values instead of Option[Location] to speed up location hit check
|
|
19
27
|
at = at.else {Location("^lsp", -7, -7)}
|
|
20
28
|
definedAt = definedAt.else {Location("^lsp", -7, -7)}
|
|
21
29
|
insertIdentifier = insertIdentifier
|
|
22
30
|
trackSymbols = trackSymbols
|
|
23
|
-
arrayOfResults =
|
|
31
|
+
arrayOfResults = Array.new()
|
|
32
|
+
sql = sql
|
|
33
|
+
sqlStrings = Array.new()
|
|
24
34
|
)
|
|
25
35
|
}
|
|
26
36
|
|
|
@@ -200,4 +210,4 @@ showHook(hook: ResultHook): String {
|
|
|
200
210
|
| ResolveSymbolHook(symbol, annotation, _) => "ResolveSymbolHook(...)"
|
|
201
211
|
| ResolveTypeHook(types, typeGenerics, symbol, explicitType) => "ResolveTypeHook(...)"
|
|
202
212
|
| ResolveVariantFieldHook(symbol, type, commonField) => "ResolveVariantFieldHook(...)"
|
|
203
|
-
}
|
|
213
|
+
}
|
package/core/Ordering.ff
CHANGED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
nodeMain(system: NodeSystem) {
|
|
2
|
+
let secretKey = system.arguments().grab(0)
|
|
3
|
+
let json = Json->(
|
|
4
|
+
model = "moonshotai/Kimi-K2.6"
|
|
5
|
+
messages = [
|
|
6
|
+
Json->(role = "user", content = "Can you summerize firefly-lang.org for me.")
|
|
7
|
+
]
|
|
8
|
+
tools = [
|
|
9
|
+
Json->(type = "function", function = Json->(
|
|
10
|
+
name = "web_search"
|
|
11
|
+
description = "Search the web for up-to-date information, images, or data based on a query."
|
|
12
|
+
parameters = Json->(
|
|
13
|
+
type = "object"
|
|
14
|
+
properties = Json->(
|
|
15
|
+
query = Json->(
|
|
16
|
+
type = "string"
|
|
17
|
+
description = "The search query to look up on the web."
|
|
18
|
+
)
|
|
19
|
+
)
|
|
20
|
+
required = ["query"]
|
|
21
|
+
)
|
|
22
|
+
))
|
|
23
|
+
Json->(type = "function", function = Json->(
|
|
24
|
+
name = "web_fetch"
|
|
25
|
+
description = "Fetch the contents of a URL using a GET request."
|
|
26
|
+
parameters = Json->(
|
|
27
|
+
type = "object"
|
|
28
|
+
properties = Json->(
|
|
29
|
+
url = Json->(
|
|
30
|
+
type = "string"
|
|
31
|
+
description = "The URL to fetch."
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
required = ["url"]
|
|
35
|
+
)
|
|
36
|
+
))
|
|
37
|
+
]
|
|
38
|
+
)
|
|
39
|
+
// To give a tool result: {"role": "tool", "content": "... e.g. encoded JSON", "tool_call_id": "call_123"}
|
|
40
|
+
system.httpClient().post("https://api.inceptron.io/v1/chat/completions", [
|
|
41
|
+
Pair("Content-Type", "application/json")
|
|
42
|
+
Pair("Authorization", "Bearer " + secretKey)
|
|
43
|
+
], json.write().toBuffer()) {response =>
|
|
44
|
+
Log.debug("Response ok? " + Show.show(response.ok()))
|
|
45
|
+
Log.debug(response.readJson().write(Some(" ")))
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
nodeMain(system: NodeSystem) {
|
|
2
|
+
|
|
3
|
+
let x: Float = 123.0
|
|
4
|
+
let s: String = "Hi"
|
|
5
|
+
let p = s + x
|
|
6
|
+
let r1: Int = 123.8.round().toInt()
|
|
7
|
+
Log.show(p)
|
|
8
|
+
|
|
9
|
+
let player = Human("RawFood23", None)
|
|
10
|
+
let bot = Bot(42)
|
|
11
|
+
|
|
12
|
+
let players: List[Player] = [
|
|
13
|
+
Human("RawFood23", None)
|
|
14
|
+
Human("Nokoline123", Some(system.date()))
|
|
15
|
+
bot
|
|
16
|
+
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
players.each {
|
|
20
|
+
| Human(name, None) =>
|
|
21
|
+
Log.trace(name + " is in lobby")
|
|
22
|
+
| Human(name, Some(joined)) =>
|
|
23
|
+
Log.trace(name + " joined at " + Show.show(joined))
|
|
24
|
+
| Bot(n) =>
|
|
25
|
+
Log.trace("Bot nr. " + n)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let player2 = (name = "Jogn", age = 11)
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
addPlayer(player: Player) {
|
|
33
|
+
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
data Player {
|
|
37
|
+
Human(
|
|
38
|
+
name: String
|
|
39
|
+
joined: Option[Date]
|
|
40
|
+
)
|
|
41
|
+
Bot(
|
|
42
|
+
number: Int
|
|
43
|
+
)
|
|
44
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
dependency ff:postgresql:0.0.0
|
|
2
|
+
|
|
3
|
+
import Pg from ff:postgresql
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
testSql(connection: PgConnection): List[String] {
|
|
7
|
+
connection.statement("""
|
|
8
|
+
-- Comment
|
|
9
|
+
select *, benefit, g.deleted, 'Fooo', 123
|
|
10
|
+
from guide."GuideHistory" g
|
|
11
|
+
join guide."GuideDepartment" GD on g.id = GD.guideid
|
|
12
|
+
where g.benefit is not null and $name = '0x42' and true
|
|
13
|
+
""")
|
|
14
|
+
.withInt("name", 34)
|
|
15
|
+
.map {row =>
|
|
16
|
+
row.getString("name").grab()
|
|
17
|
+
}
|
|
18
|
+
}
|
package/lsp/.firefly/package.ff
CHANGED
package/lsp/CompletionHandler.ff
CHANGED
|
@@ -3,6 +3,9 @@ import Unification from ff:compiler
|
|
|
3
3
|
import Environment from ff:compiler
|
|
4
4
|
import Syntax from ff:compiler
|
|
5
5
|
import Handler
|
|
6
|
+
import Sql
|
|
7
|
+
import SqlSuggestion
|
|
8
|
+
import SqlStatement
|
|
6
9
|
|
|
7
10
|
data CompletionInfo(
|
|
8
11
|
label: String
|
|
@@ -15,6 +18,7 @@ data CompletionInfo(
|
|
|
15
18
|
expectedType: Option[Type]
|
|
16
19
|
secondarySort: Int = 5
|
|
17
20
|
insertion: Option[Pair[Int, String]] = None
|
|
21
|
+
sql: Bool = False
|
|
18
22
|
)
|
|
19
23
|
|
|
20
24
|
data ImportSymbolsInfo(
|
|
@@ -35,7 +39,10 @@ handleCompletion(
|
|
|
35
39
|
toplevel: Bool
|
|
36
40
|
followedByOpenBracket: Bool
|
|
37
41
|
importSymbols: ImportSymbolsInfo
|
|
42
|
+
sqlStatement: Option[Pair[Location, SqlStatement]]
|
|
43
|
+
sqlData: SqlData
|
|
38
44
|
): Json {
|
|
45
|
+
sqlStatement.map {| Pair(l, s) => completionsToJson(sqlCompletion(l, s, sqlData))}.else:
|
|
39
46
|
let topLevelCompletions = if(!toplevel) {[]} else {toplevelCompletion(lspHook)}
|
|
40
47
|
let patternCompletions = lspHook.results().collectFirst {
|
|
41
48
|
| InferPatternHook h =>
|
|
@@ -195,10 +202,14 @@ completionsToJson(completions: List[CompletionInfo]): Json {
|
|
|
195
202
|
let isDefinition = ["let ", "mutable ", "function "].any {i.snippet.startsWith(_)}
|
|
196
203
|
let isParameter = i.snippet.endsWith(" = ")
|
|
197
204
|
let isImport = i.documentation == "// Imports this module"
|
|
198
|
-
let sortText = if(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
205
|
+
let sortText = if(i.sql && i.extra == "") {
|
|
206
|
+
i.secondarySort + i.label.lower()
|
|
207
|
+
} else {
|
|
208
|
+
if(isParameter || isDefinition || isImport) {0} else {9 - (
|
|
209
|
+
isVariable.toInt() + isUnqualified.toInt() +
|
|
210
|
+
isAlpha.toInt() + isLower.toInt() + isMember.toInt()
|
|
211
|
+
)} + if(isMember) {"1"} else {"0"} + i.secondarySort + i.label.lower()
|
|
212
|
+
}
|
|
202
213
|
let preselect = !isDefinition && Pair(i.type, i.expectedType).{
|
|
203
214
|
| Pair(TConstructor(_, n1, _), Some(TConstructor(_, n2, _))) => n1 == n2
|
|
204
215
|
| _ => False
|
|
@@ -206,6 +217,16 @@ completionsToJson(completions: List[CompletionInfo]): Json {
|
|
|
206
217
|
Json.object()
|
|
207
218
|
// Namespace or Property or Constructor or EnumMember or Constructor or Method/Function or Field/Variable
|
|
208
219
|
.with("kind"
|
|
220
|
+
if(i.sql) {
|
|
221
|
+
if(i.secondarySort == 1) {15} else:
|
|
222
|
+
if(i.secondarySort == 2) {23} else:
|
|
223
|
+
if(i.secondarySort == 3) {7} else:
|
|
224
|
+
if(i.secondarySort == 4) {5} else:
|
|
225
|
+
if(i.secondarySort == 5) {6} else:
|
|
226
|
+
if(i.secondarySort == 8) {3} else:
|
|
227
|
+
if(i.secondarySort == 9) {15} else:
|
|
228
|
+
9
|
|
229
|
+
} else:
|
|
209
230
|
if(isImport) {2} else:
|
|
210
231
|
if(shownType == "") {3} else:
|
|
211
232
|
if(isParameter) {10} else:
|
|
@@ -218,14 +239,18 @@ completionsToJson(completions: List[CompletionInfo]): Json {
|
|
|
218
239
|
.with("preselect", preselect)
|
|
219
240
|
.with("label", i.label)
|
|
220
241
|
.with("labelDetails", Json.object()
|
|
221
|
-
.with("detail", i.
|
|
242
|
+
.with("detail", if(i.sql) {i.extra} else {
|
|
243
|
+
i.extra + if(shownType == "") {""} else {": " + shownType}
|
|
244
|
+
})
|
|
222
245
|
.with("description", i.more)
|
|
223
246
|
)
|
|
224
247
|
.with("insertText", i.snippet)
|
|
225
248
|
.with("insertTextFormat", 2 /* Snippet */)
|
|
226
249
|
.with("documentation", Json.object()
|
|
227
250
|
.with("kind", "markdown")
|
|
228
|
-
.with("value",
|
|
251
|
+
.with("value",
|
|
252
|
+
if(i.sql) {"```sql\n"} else {"```\n"} + i.documentation + "\n```"
|
|
253
|
+
)
|
|
229
254
|
)
|
|
230
255
|
.with("additionalTextEdits", i.insertion.toList().map {| Pair(line, text) => Json.object()
|
|
231
256
|
.with("range", Json->(
|
|
@@ -237,6 +262,87 @@ completionsToJson(completions: List[CompletionInfo]): Json {
|
|
|
237
262
|
})
|
|
238
263
|
}
|
|
239
264
|
|
|
265
|
+
sqlCompletion(at: Location, sqlStatement: SqlStatement, data: SqlData): List[CompletionInfo] {
|
|
266
|
+
let tokens = Sql.tokenize(sqlStatement.string)
|
|
267
|
+
let line = 1 + at.line - sqlStatement.at.line
|
|
268
|
+
let column = if(at.line == sqlStatement.at.line) {1 + at.column - sqlStatement.at.column} else {at.column}
|
|
269
|
+
let suggestions = SqlSuggestion.suggest(data, tokens, line, column)
|
|
270
|
+
function fixQuotes(snippet: String): String {
|
|
271
|
+
if(suggestions.second) {snippet.replace("\"", "")} else {snippet}
|
|
272
|
+
}
|
|
273
|
+
suggestions.first.map {
|
|
274
|
+
| SqlSuggestionFunction(l, signature, documentation)@suggestion =>
|
|
275
|
+
CompletionInfo(
|
|
276
|
+
label = l
|
|
277
|
+
extra = signature
|
|
278
|
+
more = ""
|
|
279
|
+
snippet = fixQuotes(Sql.quote(l) + "($0)")
|
|
280
|
+
member = False
|
|
281
|
+
type = TConstructor(Location("", 0, 0), "", [])
|
|
282
|
+
documentation = documentation
|
|
283
|
+
expectedType = None
|
|
284
|
+
sql = True
|
|
285
|
+
secondarySort = suggestion.secondarySort()
|
|
286
|
+
)
|
|
287
|
+
| SqlSuggestionJoin(l, schema, snippet)@suggestion =>
|
|
288
|
+
CompletionInfo(
|
|
289
|
+
label = l
|
|
290
|
+
extra = ""
|
|
291
|
+
more = schema
|
|
292
|
+
snippet = fixQuotes(snippet)
|
|
293
|
+
member = False
|
|
294
|
+
type = TConstructor(Location("", 0, 0), "", [])
|
|
295
|
+
documentation = snippet
|
|
296
|
+
expectedType = None
|
|
297
|
+
sql = True
|
|
298
|
+
secondarySort = suggestion.secondarySort()
|
|
299
|
+
)
|
|
300
|
+
| SqlSuggestionRegular(l, display, documentation)@suggestion =>
|
|
301
|
+
CompletionInfo(
|
|
302
|
+
label = l
|
|
303
|
+
extra = ""
|
|
304
|
+
more = display
|
|
305
|
+
snippet = fixQuotes(Sql.quote(l))
|
|
306
|
+
member = False
|
|
307
|
+
type = TConstructor(Location("", 0, 0), "", [])
|
|
308
|
+
documentation = documentation
|
|
309
|
+
expectedType = None
|
|
310
|
+
sql = True
|
|
311
|
+
secondarySort = suggestion.secondarySort()
|
|
312
|
+
)
|
|
313
|
+
| SqlSuggestionColumnNames(required, columns)@suggestion =>
|
|
314
|
+
let comment =
|
|
315
|
+
if(required) {"-- required columns\n"} elseIf {columns.size() > 1} {"-- all columns\n"} else {""}
|
|
316
|
+
CompletionInfo(
|
|
317
|
+
label = columns.map {_.first}.join(", ")
|
|
318
|
+
extra = ""
|
|
319
|
+
more = ""
|
|
320
|
+
snippet = fixQuotes(columns.map {Sql.quote(_.first)}.join(", "))
|
|
321
|
+
member = False
|
|
322
|
+
type = TConstructor(Location("", 0, 0), "", [])
|
|
323
|
+
documentation = comment + columns.map {_.second}.join("\n")
|
|
324
|
+
expectedType = None
|
|
325
|
+
sql = True
|
|
326
|
+
secondarySort = suggestion.secondarySort()
|
|
327
|
+
)
|
|
328
|
+
| SqlSuggestionColumnSetters(columns)@suggestion =>
|
|
329
|
+
CompletionInfo(
|
|
330
|
+
label = columns.map {_.first + " = "}.join(", ")
|
|
331
|
+
extra = ""
|
|
332
|
+
more = ""
|
|
333
|
+
snippet = fixQuotes(columns.pairs().map {| Pair(i, c) =>
|
|
334
|
+
Sql.quote(c.first) + " = " + if(i == 0) {"$0"} else {""}
|
|
335
|
+
}.join(",\n"))
|
|
336
|
+
member = False
|
|
337
|
+
type = TConstructor(Location("", 0, 0), "", [])
|
|
338
|
+
documentation = columns.map {_.second}.join("\n")
|
|
339
|
+
expectedType = None
|
|
340
|
+
sql = True
|
|
341
|
+
secondarySort = suggestion.secondarySort()
|
|
342
|
+
)
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
240
346
|
importCompletion(moduleKeys: List[ModuleKey]): List[CompletionInfo] {
|
|
241
347
|
moduleKeys.map {moduleKey =>
|
|
242
348
|
let label = moduleKey.folders.map {_ + "."}.join() + moduleKey.name
|