Multiple changes:

- Move to a Python process for the LanguageLink client [fixes #1, presumably]
- Finish a first rough draft of the booklet [fixes #4]
This commit is contained in:
2022-06-11 18:43:17 +02:00
parent acded68da5
commit 6369d15e93
39 changed files with 3977 additions and 56 deletions

14
carp/src/Pipfile Normal file
View File

@@ -0,0 +1,14 @@
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true
[dev-packages]
[packages]
flask = "*"
requests = "*"
msgpack = "*"
[requires]
python_version = "3"

View File

178
carp/src/bridge/bridge.py Normal file
View File

@@ -0,0 +1,178 @@
import argparse
import threading
import sys
import hooks
from bridge.hooks import *
from bridge.object_registry import registry
def pbbreak():
print("Breaking now")
breakpoint()
print("Continuing")
class EvalCommand:
statements = ""
bindings = {}
commandId = 0
def __init__(self, commandId, statements, bindings):
self.statements = statements
self.commandId = commandId
self.bindings = bindings
def execute_using_env(self, env):
try:
self.execute()
except Exception as err:
self.perform_proceed_action(notify_error(err,self))
def perform_proceed_action(self, actionDict):
actionSymbol = actionDict['action']
if actionSymbol == "IGNORE":
pass
if actionSymbol == "DROP_QUEUE":
bridge.globals.globalCommandList.drop_queue()
if actionSymbol == "REPLACE_COMMAND":
commandDict = actionDict["command"]
bridge.globals.globalCommandList.push_command_at_first(EvalCommand(
commandDict["commandId"],
commandDict["statements"],
commandDict["bindings"]))
def command_id(self):
return self.commandId
def execute(self):
bridge.globals.proc.evaluate(self.statements)
class Logger():
def log(self, msg):
print(str(msg), file=sys.stderr, flush=True)
class NoLogger():
def log(self, msg):
pass
# This List is thought to be multi-producer and single-consumer. For optimal results wait for push_command return value to push another command that depends on the previous one.
class CommandList:
currentCommandIndex = 0
commandList = []
listLock = threading.Lock()
consumeSemaphore = threading.Semaphore(value=0)
# This method locks the thread until the command has been succesfully appended to the list. Even though that it has a lock inside, we do not expect long waiting time.
def push_command(self, aCommand):
self.listLock.acquire()
self.commandList.append(aCommand)
commandIndex = len(self.commandList) - 1
self.listLock.release()
self.consumeSemaphore.release()
return commandIndex
def push_command_at_first(self, aCommand):
self.listLock.acquire()
self.commandList.insert(self.currentCommandIndex, aCommand)
self.listLock.release()
self.consumeSemaphore.release()
return self.currentCommandIndex
def drop_queue(self):
self.listLock.acquire()
self.consumeSemaphore = threading.Semaphore(value=0)
self.currentCommandIndex = len(self.commandList)
self.listLock.release()
def consume_command(self):
repeatMonitorFlag = True
while repeatMonitorFlag:
self.consumeSemaphore.acquire()
self.listLock.acquire()
repeatMonitorFlag = False
if(self.currentCommandIndex >= len(self.commandList)):
repeatMonitorFlag = True
self.listLock.release()
command = self.commandList[self.currentCommandIndex]
self.currentCommandIndex += 1
self.listLock.release()
return command
def get_current_command(self):
if self.currentCommandIndex == 0:
return None
self.listLock.acquire()
command = self.commandList[self.currentCommandIndex-1]
self.listLock.release()
return command
def get_command_list(self):
self.listLock.acquire()
listCopy = self.commandList.copy()
self.listLock.release()
return listCopy
#### UTILS FUNCTIONS
def clean_locals_env():
return locals()
def deserialize(text):
result = bridge.globals.msg_service.serializer.deserialize(text)
bridge.globals.logger.log("DESERIALISE (bridge): " + str(result))
if registry().isProxy(result):
result = registry().resolve(result['__pyid__'])
return result
def enqueue_command(data):
bridge.globals.globalCommandList.push_command(EvalCommand(
data["commandId"],
data["statements"],
{k: deserialize(v) for k, v in data["bindings"].items()}))
def run_bridge():
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--port", required=False,
help="port to be used for receiving instructions")
ap.add_argument("-o", "--pharo", required=True,
help="port to be used for sending notifications back to pharo")
ap.add_argument("-m", "--method", required=False,
help="identifier for communication protocol strategy http or msgpack")
ap.add_argument("--log", required=False, const=True, nargs="?",
help="enable logging")
args = vars(ap.parse_args())
bridge.globals.pharoPort = args["pharo"]
if args["log"]:
bridge.globals.logger = Logger()
else:
bridge.globals.logger = NoLogger()
bridge.globals.pyPort = args["port"]
bridge.globals.globalCommandList = CommandList()
globalCommandList = bridge.globals.globalCommandList
bridge.globals.proc = carp.start_carp_proc()
env = clean_locals_env()
msg_service = None
if args["port"] == None:
args["port"] = '0'
if args["method"] == None:
args["method"] = 'http'
if args["method"] == 'http':
from bridge import flask_platform
msg_service = flask_platform.build_service(int(args["port"]), int(args["pharo"]), enqueue_command)
elif args["method"] == 'msgpack':
from bridge import msgpack_socket_platform
msg_service = msgpack_socket_platform.build_service(int(args["port"]), int(args["pharo"]), enqueue_command)
else:
raise Exception("Invalid communication strategy.")
bridge.globals.msg_service = msg_service
msg_service.start()
bridge.globals.logger.log("PYTHON: Start consuming commands")
while True:
command = globalCommandList.consume_command()
bridge.globals.logger.log("PYTHON: Executing command " + command.command_id())
bridge.globals.logger.log("PYTHON: bindings: " + str(command.bindings))
bridge.globals.logger.log("PYTHON: " + command.statements)
command.execute_using_env(env)
bridge.globals.logger.log("PYTHON: Finished command execution")
if __name__ == "__main__":
run_bridge()

13
carp/src/bridge/carp.py Normal file
View File

@@ -0,0 +1,13 @@
import subprocess
class CarpProc:
def __init__(self):
self.proc = subprocess.Popen(['carp'])
def evaluate(self, statements):
self.proc.stdin.send(statements)
def start_carp_proc():
return CarpProc()

View File

@@ -0,0 +1,73 @@
from flask import Flask, request
import http.client
import json
import threading
import bridge.globals
import bridge.utils
from bridge import json_encoder
import sys
import logging
import requests
class FlaskMsgService:
def __init__(self, port, pharo_port, feed_callback):
self.serializer = json_encoder.JsonSerializer()
log = logging.getLogger('werkzeug')
log.setLevel(logging.ERROR)
self.thread = None
self.port = port
self.pharo_port = pharo_port
self.feed_callback = feed_callback
self.app = Flask('carp_bridge')
self.app.use_reloader=False
self.session = requests.Session()
self.session.trust_env = True
@self.app.route("/ENQUEUE", methods=["POST"])
def eval_expression():
data = request.get_json(force=True)
self.feed_callback(data)
return "{}"
@self.app.route("/IS_ALIVE", methods=["POST"])
def status_endpoint():
return "{}"
def addMapping(self, key_type, mapping_function):
json_encoder.addMapping(key_type, mapping_function)
def _start(self):
try:
self.app.run(port=self.port)
except OSError as err:
bridge.globals.logger.log('Critical Error:' + str(err))
exit(42)
def start(self):
self.thread = threading.Thread(target=self._start, args=())
self.thread.daemon = True
self.thread.start()
def is_running(self):
return self.thread != None
def stop(self):
pass
def send_async_message(self, msg):
self.send_sync_message(msg)
def send_sync_message(self, msg):
msg['__sync'] = bridge.utils.random_str()
bridge.globals.logger.log("SYNC_MSG: " + json.dumps(msg))
response = self.session.post(
'http://localhost:' + str(self.pharo_port) + '/' + msg['type'],
data=json.dumps(msg),
headers={'content-type': 'application/json'},
allow_redirects=True).content.decode('utf-8')
bridge.globals.logger.log("SYNC_ANS: " + response)
return json.loads(response)
def build_service(port, pharo_port, feed_callback):
return FlaskMsgService(port, pharo_port, feed_callback)

View File

50
carp/src/bridge/hooks.py Normal file
View File

@@ -0,0 +1,50 @@
from flask import Flask, request
import http.client
import argparse
import sys
import traceback
import bridge.globals
def serialize(obj):
return bridge.globals.msg_service.serializer.serialize(obj)
def deserialize(text):
return bridge.globals.msg_service.serializer.deserialize(text)
def observer(commandId, observerId):
return lambda obj: notify_observer(obj, commandId, observerId)
#### NOTIFICATION FUNCTIONS
def notify(obj, notificationId):
bridge.globals.logger.log("PYTHON: Notify " + str(notificationId))
data = {}
data["type"] = "EVAL"
data["id"] = notificationId
data["value"] = serialize(obj)
bridge.globals.msg_service.send_async_message(data)
def notify_observer(obj, commandId, observerId):
bridge.globals.logger.log("PYTHON: Notify observer " + str(commandId) + " " + str(observerId))
data = {}
data["type"] = "CALLBACK"
data["commandId"] = commandId
data["observerId"] = observerId
data["value"] = serialize(obj)
rawValue = bridge.globals.msg_service.send_sync_message(data)['value']
return deserialize(rawValue)
def notify_error(ex, command):
bridge.globals.logger.log("Error on command: " + str(command.command_id()))
bridge.globals.logger.log("Exception: " + str(ex))
data = {}
data["type"] = "ERR"
data["errMsg"] = str(ex)
data["trace"] = traceback.format_exc(100)
data["commandId"] = command.command_id()
return bridge.globals.msg_service.send_sync_message(data)
def bridge_inspect(obj):
if hasattr(obj,'__dict__'):
return obj.__dict__
else:
return {}

View File

@@ -0,0 +1,28 @@
import json
import io
from bridge.object_registry import registry
mapper = {}
def addMapping(key_type, mapping_function):
mapper[key_type] = mapping_function
class JsonEncoder(json.JSONEncoder):
def __init__(self, *args, **kwargs):
json.JSONEncoder.__init__(self, *args, **kwargs)
self.mapper = mapper
def default(self, obj):
if type(obj) in self.mapper:
return self.mapper[type(obj)](obj)
return {
'__pyclass__': type(obj).__name__,
'__pyid__': registry().register(obj)
}
class JsonSerializer:
def serialize(self, obj):
return json.dumps(obj, cls=JsonEncoder)
def deserialize(self, text):
return json.loads(text)

View File

@@ -0,0 +1,41 @@
import msgpack
from bridge.object_registry import registry
primitive_types = [
type(None),
bool,
int,
bytes,
str,
dict,
list,
memoryview,
bytearray]
mapper = {}
def addMapping(key_type, mapping_function):
mapper[key_type] = mapping_function
class MsgPackSerializer:
def __init__(self):
self.primitive_types = primitive_types
def mapper(self):
return mapper
def default(self, obj):
if type(obj) in self.primitive_types:
return obj
if type(obj) in self.mapper():
return self.mapper()[type(obj)](obj)
return {
'__pyclass__': type(obj).__name__,
'__pyid__': registry().register(obj)
}
def serialize(self, obj):
return msgpack.packb(obj, default=self.default, use_bin_type=True)
def deserialize(self, binary):
return msgpack.unpackb(binary, raw=False)

View File

@@ -0,0 +1,120 @@
import msgpack
import socket
import _thread
import threading
import time
import sys
import bridge.globals
from bridge import stoppable_thread, msgpack_serializer
from uuid import uuid1
# Messages supported by this sockets must be Dictionaries. This is because we use special key __sync to know if it is
# a synchronized message or not. If it is we hook a semaphore to that id under the __sync key and after we receive the
# value we store there the return message and signal the semaphore.
class MsgPackSocketPlatform:
def __init__(self, port):
self.port = port
self.client = None
self.serializer = msgpack_serializer.MsgPackSerializer()
self.unpacker = msgpack.Unpacker(raw=False)
self.packer = msgpack.Packer(use_bin_type=True)
self.sync_table = {}
self.async_handlers = {}
def addMapping(self, key_type, mapping_function):
msgpack_serializer.addMapping(key_type, mapping_function)
def set_handler(self, msg_type, async_handler):
self.async_handlers[msg_type] = async_handler
def prim_handle(self):
try:
bridge.globals.logger.log("loop func")
data = self.client.recv(2048)
if len(data) == 0:
time.sleep(0.005)
else:
self.unpacker.feed(data)
for msg in self.unpacker:
bridge.globals.logger.log("prim handle message")
self.prim_handle_msg(msg)
except OSError:
bridge.globals.logger.log("OSError: " + str(err))
self.stop()
sys.exit()
exit(-1)
except Exception as err:
bridge.globals.logger.log("ERROR message: " + str(err))
def setup_func(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client.connect(('localhost', self.port))
def stop(self):
if self.thread is not None:
self.thread.stop()
if self.client is not None:
self.client.close()
self.client = None
def send_answer(self, msg, answer):
if answer['type'] != msg['type']:
raise Exception('Type mismatch')
answer['__sync'] = msg['__sync']
self.send_async_message(answer)
def is_running(self):
return self.client != None
def prim_handle_msg(self, raw_msg):
msg = raw_msg
msg_type = msg['type']
if msg_type in self.async_handlers:
self.async_handlers[msg['type']](msg)
elif is_sync_msg(msg):
sync_id = message_sync_id(msg)
semaphore = self.sync_table[sync_id]
self.sync_table[sync_id] = msg
semaphore.release()
else:
bridge.globals.logger.log("Error! Msg couldnt be handled")
raise Exception('Message couldn''t be handled')
def start(self):
self.thread = stoppable_thread.StoppableThread(
loop_func= self.prim_handle,
setup_func= self.setup_func)
self.thread.start()
time.sleep(.1)
def send_async_message(self, msg):
self.client.send(self.packer.pack(msg))
def send_sync_message(self, msg):
sync_id = mark_message_as_sync(msg)
semaphore = threading.Semaphore(value=0)
self.sync_table[sync_id] = semaphore
self.send_async_message(msg)
semaphore.acquire()
ans = self.sync_table[sync_id]
del self.sync_table[sync_id]
return ans
def is_sync_msg(msg):
return '__sync' in msg
def message_sync_id(msg):
return msg['__sync']
def mark_message_as_sync(msg):
sync_id = uuid1().hex
msg['__sync'] = sync_id
return sync_id
def build_service(port, pharo_port, feed_callback):
service = MsgPackSocketPlatform(pharo_port)
service.set_handler('ENQUEUE',feed_callback)
service.set_handler('IS_ALIVE', lambda msg: service.send_answer(msg, {'type': 'IS_ALIVE'}))
return service

View File

@@ -0,0 +1,88 @@
import bridge.globals
from uuid import uuid1
def ensure_global_registry():
if not hasattr(bridge.globals, 'ObjectRegistry'):
bridge.globals.ObjectRegistry = Registry()
def registry():
return bridge.globals.ObjectRegistry
primitive = (int, str, bool)
def is_primitive(obj):
return isinstance(obj, primitive)
class Registry():
def __init__(self):
self.idToObjMap = {}
self.objToIdMap = {}
def hasId(self, anId):
return anId in self.idToObjMap
def createNewObjId(self):
return uuid1().hex
def register(self, obj):
if obj is None or is_primitive(obj):
return 0
if id(obj) in self.objToIdMap:
return self.objToIdMap[id(obj)]
else:
return self._register(obj, self.createNewObjId())
def register_with_id(self, obj, newObjId):
if obj is None or is_primitive(obj):
return RegisterForbiddenObject(obj)
if id(obj) in self.objToIdMap:
objId = self.objToIdMap[id(obj)]
if objId == newObjId:
return newObjId
else:
raise RegisterWithDifferentIdError(obj, newObjId)
else:
return self._register(obj, newObjId)
def resolve(self, objId):
if objId in self.idToObjMap:
return self.idToObjMap[objId]
else:
raise ResolveUnknownObject(objId)
def _register(self, obj, newObjId):
self.idToObjMap[newObjId] = obj
self.objToIdMap[id(obj)] = newObjId
return newObjId
def clean(self, objId):
obj = self.idToObjMap[objId]
del self.idToObjMap[objId]
del self.objToIdMap[id(obj)]
def isProxy(self, anObject):
is_proxy = False
if isinstance(anObject, dict):
if len(anObject.keys()) == 2 and ('__pyclass__' in anObject) and ('__pyid__' in anObject):
is_proxy = True
return is_proxy
class RegistryError(Exception):
pass
class RegisterWithDifferentIdError(RegistryError):
def __init__(self, obj, newId):
RegistryError.__init__(self,"Attempting to register object {0} with ID {1} with different ID {2}.".format(type(obj).__name__, registry().register(obj), newId))
class ResolveUnknownObject(RegistryError):
def __init__(self, objId):
RegistryError.__init__(self,"Attempting to resolve unknown object with id {0}.".format(objId))
class RegisterForbiddenObject(RegistryError):
def __init__(self, obj):
RegistryError.__init__(self,"Attempting to register forbidden object of type {0}.".format(type(obj).__name__))
ensure_global_registry()

View File

@@ -0,0 +1,24 @@
import threading
class StoppableThread(threading.Thread):
def __init__(self, loop_func, setup_func):
threading.Thread.__init__(self)
self._stop_event = threading.Event()
self.daemon = True
self.loop_func = loop_func
self.setup_func = setup_func
# function using _stop function
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.isSet()
def run(self):
self.setup_func()
while True:
if self.stopped():
return
self.loop_func()

View File

@@ -0,0 +1,36 @@
import argparse
import threading
import time
# Calculate the factorial
def factorial(n, t):
time.sleep(n*t/4)
print("Start: " + str(t) + ": " + str(n))
if n == 1:
res = 1
if t == 1:
print("Feel free to break here")
else:
res = n * factorial(n-1, t)
return res
# Calculate the factorial and print the result
def factorial_thread(n, t):
time.sleep(2)
result = factorial(n, t)
print("Thread " + str(t) + " = "+str(result))
def launch_factorials(n):
threads = []
print("Calculate: "+str(n))
breakpoint()
for i in range(n):
threads.append(threading.Thread(target=factorial_thread, args=(n+i, i+1)))
threads[-1].start()
print("Wait for the results")
for thread in threads:
thread.join()
print("Done")

2
carp/src/bridge/tmp.py Normal file
View File

@@ -0,0 +1,2 @@
import time
time.sleep(3)

5
carp/src/bridge/utils.py Normal file
View File

@@ -0,0 +1,5 @@
from uuid import uuid1
def random_str():
return uuid1().hex

View File

@@ -0,0 +1,17 @@
(load "/Users/veitheller/Documents/Code/Github/carp/archive/socket/sockets.carp")
(use Socket)
(defn main []
(let-do [port (Maybe.from (from-string &(Maybe.from (nth &System.args 1) @"")) 0)]
(IO.println &(fmt "Starting server on localhost, port %d" port))
(Socket.with-server sock "127.0.0.1" port
(if (Socket.valid? &sock)
(Socket.while-connection &sock client
(IO.println &(read &client))
(send &client "hi")
(IO.println "yay"))
(IO.errorln "Server couldnt be started.")))))
(build)
(run)

4
carp/src/languagelink.py Normal file
View File

@@ -0,0 +1,4 @@
from bridge import bridge
from bridge.bridge_hooks import *
bridge.run_bridge()

View File

@@ -2,6 +2,11 @@
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [
{
@@ -14,6 +19,39 @@
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T22:22:31.801924+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T22:22:40.406467+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "3kLYI0GZDQCKnLdXBAU6hQ=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[Interlude: An Introduction to Carp]]"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
@@ -41,43 +79,6 @@
},
"string" : "[[Introduction]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T22:22:30.537898+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T22:22:30.537898+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "3kLYI0GZDQCKnLdXBAU6hQ=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : ""
},
{
"__type" : "textSnippet",
"children" : {
@@ -227,6 +228,11 @@
},
"string" : "[[Styling your AST]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
@@ -237,6 +243,113 @@
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:20.565513+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:20.565513+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "UXDVu4+dDQC/fqHFA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[Building a LanguageLink client]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:33.223032+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:33.223032+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "6dWWvI+dDQC/gM7QA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[Building a LanguageLink server]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:45.88618+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:48.608001+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "rYmTAZCdDQC/qIzPA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[What now?]]"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
@@ -264,6 +377,81 @@
},
"string" : "[[Executing code]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:07:50.665361+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:07:59.692968+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "3NNC/o+dDQC/oLtxA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[Hooking up your LanguageLink server]]"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:54.91122+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:11.691776+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "uAjiAZCdDQC/qqUDA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[A custom snippet type]]"
},
{
"__type" : "textSnippet",
"children" : {

View File

@@ -228,6 +228,11 @@
},
"string" : "[[Styling your AST]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
@@ -238,6 +243,113 @@
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:20.565513+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:20.565513+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "UXDVu4+dDQC/fqHFA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[Building a LanguageLink client]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:33.223032+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:33.223032+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "6dWWvI+dDQC/gM7QA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[Building a LanguageLink server]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:45.88618+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:48.608001+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "rYmTAZCdDQC/qIzPA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[What now?]]"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
@@ -265,6 +377,118 @@
},
"string" : "[[Executing code]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:07:50.665361+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:07:59.692968+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "3NNC/o+dDQC/oLtxA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[Hooking up your LanguageLink server]]"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:54.91122+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:11.691776+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "uAjiAZCdDQC/qqUDA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[A custom snippet type]]"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:03.097269+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:05.781133+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "j+IkapCdDQCBVgDCA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "[[Fin]]"
},
{
"__type" : "textSnippet",
"children" : {

View File

@@ -325,14 +325,14 @@
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T17:07:38.104346+02:00"
"dateAndTimeString" : "2022-06-11T16:35:43.289314+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "Ddc1ljyZDQCZq2mSDqn2mw=="
},
"code" : "; this is what we will be able to do\r(IO.defn hello-world []\r (IO.println \"Hello world!\"))"
"code" : "; this is what we will be able to do\r(defn hello-world []\r (IO.println \"Hello world!\"))"
},
{
"__type" : "textSnippet",

View File

@@ -325,7 +325,7 @@
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T17:08:04.346367+02:00"
"dateAndTimeString" : "2022-06-11T16:35:43.289314+02:00"
}
},
"uid" : {
@@ -359,7 +359,7 @@
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T16:54:20.656267+02:00"
"dateAndTimeString" : "2022-06-11T17:10:18.677811+02:00"
}
},
"uid" : {

View File

@@ -0,0 +1,113 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T11:30:43.257961+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:48:16.142343+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "JUkMyTyZDQCZxrrZDqn2mw=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Getting code to execute is most likely the most tricky part of adding a language to GT. Most of the code in the Carp IDE deals with handling that part of the IDE experience. Additionally, LanguageLink requires a custom server setup, which needed to be written outside of GT."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:48:20.869905+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:48:46.359725+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "dwEUdoqdDQC+EJoFA3UANg=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Because both parts of this process make a cohesive whole, I split this chapter into two sub-chapters, [[B"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T17:10:47.300048+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T17:10:47.300048+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "Executing code"
},
"uid" : {
"__type" : "uuid",
"uuid" : "647f0bc9-3c99-0d00-99c5-5d710ea9f69b"
}
}

View File

@@ -18,7 +18,7 @@
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T17:10:53.313378+02:00"
"dateAndTimeString" : "2022-06-11T11:30:43.257961+02:00"
}
},
"editEmail" : {
@@ -29,7 +29,7 @@
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-04-17T17:10:53.833743+02:00"
"dateAndTimeString" : "2022-06-11T17:48:16.142343+02:00"
}
},
"uid" : {
@@ -39,7 +39,44 @@
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "TODO"
"string" : "Getting code to execute is most likely the most tricky part of adding a language to GT. Most of the code in the Carp IDE deals with handling that part of the IDE experience. Additionally, LanguageLink requires a custom server setup, which needed to be written outside of GT."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:48:20.869905+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:02.268331+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "dwEUdoqdDQC+EJoFA3UANg=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Because both parts of this process make a cohesive whole, I split this chapter into two sub-chapters, [[Building a LanguageLink client]] and [[Building a LanguageLink server]]."
}
]
},

View File

@@ -0,0 +1,258 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:27.48233+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:42.790324+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "n0WyA5CdDQC/sEIUA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Now that we have a LanguageLink server, we are all set, right? Well, not quite."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:49.137549+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:10:53.048149+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "YxldBZCdDQC/s15wA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Usually, a LanguageLink server is used within snippets as a driver for code execution. While you can use it yourself to execute some custom code and find some pleasure in that, we will first need an interface to type code *into* to make it truly worth our while."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:10:55.085183+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:11:56.629038+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "ChpOCZCdDQC/tYwmA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "But I understand that after all of the effort of building a LanguageLink implementation for your target youre itching to try it out, so Ill give you a little teaser of how its going to be used in the snippet:"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:11:58.378929+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:12:53.87069+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "BW4QDZCdDQC/tz6wA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "{{gtMethod:GtCarpCoderModel>>#bindAndExecute:|expanded}}"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:13:00.938416+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:13:26.816542+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "LBHBEJCdDQC/9sJRA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "This means that a simple snippet to test your LanguageLink implementation might look like this:"
},
{
"__type" : "pharoSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:13:37.920717+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:18:19.754957+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "EjsQE5CdDQC/+NLCA8ExpA=="
},
"code" : "sourceString := '(IO.println \"Hello World!\")'.\t\"change this to your language\"\r\rapplication := CarpApplication uniqueInstance. \"change this to your application, might need to initialize the unique instance\"\rapplication isRunning ifFalse: [ application start ].\rcommandFactory := application newCommandFactory.\r\rcommandFactory\r\t<< sourceString;\r\tsendAndWait"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:20.062163+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:20.062163+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "What now?"
},
"uid" : {
"__type" : "uuid",
"uuid" : "9b9eb103-909d-0d00-bfaf-1b1203c131a4"
}
}

View File

@@ -0,0 +1,295 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:27.48233+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:42.790324+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "n0WyA5CdDQC/sEIUA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Now that we have a LanguageLink server, we are all set, right? Well, not quite."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:49.137549+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:10:53.048149+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "YxldBZCdDQC/s15wA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Usually, a LanguageLink server is used within snippets as a driver for code execution. While you can use it yourself to execute some custom code and find some pleasure in that, we will first need an interface to type code *into* to make it truly worth our while."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:10:55.085183+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:11:56.629038+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "ChpOCZCdDQC/tYwmA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "But I understand that after all of the effort of building a LanguageLink implementation for your target youre itching to try it out, so Ill give you a little teaser of how its going to be used in the snippet:"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:11:58.378929+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:12:53.87069+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "BW4QDZCdDQC/tz6wA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "{{gtMethod:GtCarpCoderModel>>#bindAndExecute:|expanded}}"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:13:00.938416+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:13:26.816542+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "LBHBEJCdDQC/9sJRA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "This means that a simple snippet to test your LanguageLink implementation might look like this:"
},
{
"__type" : "pharoSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:13:37.920717+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:18:32.957333+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "EjsQE5CdDQC/+NLCA8ExpA=="
},
"code" : "sourceString := '(IO.println \"Hello World!\")'.\t\"change this to your language\"\r\rapplication := CarpApplication uniqueInstance.\t\"change this to your application, might need to initialize the unique instance\"\rapplication isRunning ifFalse: [ application start ].\rcommandFactory := application newCommandFactory.\r\rcommandFactory\r\t<< sourceString;\r\tsendAndWait"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:18:42.650713+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:18:48.915283+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "pPclJZCdDQCADqoCA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "And that should be all you need to get going!"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:20.062163+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:20.062163+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "What now?"
},
"uid" : {
"__type" : "uuid",
"uuid" : "9b9eb103-909d-0d00-bfaf-1b1203c131a4"
}
}

View File

@@ -0,0 +1,187 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:18:58.358497+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:19:44.830424+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "n4phA5CdDQC/rbQ7A8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "After the doozy that is setting up LanguageLink, you might think that making a custom snippet type is going to be even more effort. Ive got good news for you."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:19:51.016989+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:25:16.445558+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "Occ9KZCdDQCAEXGwA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Creating a snippet type is actually quite simple. Almost all of the code for Carp is in the Carp package, under the tag Lepiter (TODO: gtPackage annotation would be great). The most important class is likely {{gtClass:LeCarpSnippet}}, because like {{gtClass:CarpApplication}} for LanguageLink, this class is the central player around which the rest of the team organizes."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:25:29.637968+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:29:22.376041+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "pS1HPZCdDQCAOUdiA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Most of the code you will write will just be specialization over readily-available Lepiter classes. The only things that will be truly custom will most likely be your version of {{gtClass:LeExternalServerStrategy}} (in the case of Carp that is {{gtClass:LeCarpApplicationStrategy}}), which will bridge the gap between your LanguageLink application and the snippet itself, and your {{gtClass:GtSourceCoder}}, which"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:28:08.711515+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:28:15.191912+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "Dv7PRJCdDQCASGWFA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "But more about that in the next section!"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:14.768068+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:14.768068+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "A custom snippet type"
},
"uid" : {
"__type" : "uuid",
"uuid" : "6ad66003-909d-0d00-bfac-dd3803c131a4"
}
}

View File

@@ -0,0 +1,187 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:18:58.358497+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:19:44.830424+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "n4phA5CdDQC/rbQ7A8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "After the doozy that is setting up LanguageLink, you might think that making a custom snippet type is going to be even more effort. Ive got good news for you."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:19:51.016989+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:25:16.445558+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "Occ9KZCdDQCAEXGwA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Creating a snippet type is actually quite simple. Almost all of the code for Carp is in the Carp package, under the tag Lepiter (TODO: gtPackage annotation would be great). The most important class is likely {{gtClass:LeCarpSnippet}}, because like {{gtClass:CarpApplication}} for LanguageLink, this class is the central player around which the rest of the team organizes."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:25:29.637968+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:29:42.230718+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "pS1HPZCdDQCAOUdiA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Most of the code you will write will just be specialization over readily-available Lepiter classes. The only things that will be truly custom will most likely be your version of {{gtClass:LeExternalServerStrategy}} (in the case of Carp that is {{gtClass:LeCarpApplicationStrategy}}), which will bridge the gap between your LanguageLink application and the snippet itself, and your {{gtClass:GtSourceCoder}} ({{gtClass:GtCarpCoderModel}})."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:28:08.711515+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:28:15.191912+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "Dv7PRJCdDQCASGWFA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "But more about that in the next section!"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:14.768068+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:09:14.768068+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "A custom snippet type"
},
"uid" : {
"__type" : "uuid",
"uuid" : "6ad66003-909d-0d00-bfac-dd3803c131a4"
}
}

View File

@@ -0,0 +1,150 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:59:53.327975+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:01:42.598848+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "bUpMu4+dDQC/fPzrA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Theoretically, you can use any technology that supports HTTP, JSON, and possibly MessagePack to construct a LanguageLink server, and you might be tempted to just do it in the language you are targetting, especially since it is quite likely that you are comfortable in it."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:01:44.277599+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:06:06.353672+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "Yzt86I+dDQC/lywBA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "I too was tempted to go down that route before realizing that that would mean understanding and implementing the LanguageLink protocol, a task I wasnt particularly interested in. Instead, the Carp LanguageLink server uses the one provided by PythonBridge (which can be found [in the PythonBridge repository TODO: good link](github.com/feenkcom/pythonbridge)). It includes all the infrastructure needed, and the only thing that likely needs to be changed is how `EvalCommand`s are handled: in the case of Carp, a simple subprocess handler that feeds the statements into a Carp REPL and reads the result. You can inspect the custom code I wrote [in the gt4carp repository TODO: good link](https://git.veitheller.de/carpentry/gt4carp)."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:06:15.752492+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:07:19.529977+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "tJmV+I+dDQC/nrmHA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "While I understand that this is a rather terse “figure it out yourself”, I dont know the ins and outs of the LanguageLink protocol well enough to assist you any more—precisely because I took t"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:05.418793+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:05.418793+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "Building a LanguageLink server"
},
"uid" : {
"__type" : "uuid",
"uuid" : "e4a14bbb-8f9d-0d00-bf7b-383c03c131a4"
}
}

View File

@@ -0,0 +1,150 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:59:53.327975+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:01:42.598848+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "bUpMu4+dDQC/fPzrA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Theoretically, you can use any technology that supports HTTP, JSON, and possibly MessagePack to construct a LanguageLink server, and you might be tempted to just do it in the language you are targetting, especially since it is quite likely that you are comfortable in it."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:01:44.277599+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:06:06.353672+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "Yzt86I+dDQC/lywBA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "I too was tempted to go down that route before realizing that that would mean understanding and implementing the LanguageLink protocol, a task I wasnt particularly interested in. Instead, the Carp LanguageLink server uses the one provided by PythonBridge (which can be found [in the PythonBridge repository TODO: good link](github.com/feenkcom/pythonbridge)). It includes all the infrastructure needed, and the only thing that likely needs to be changed is how `EvalCommand`s are handled: in the case of Carp, a simple subprocess handler that feeds the statements into a Carp REPL and reads the result. You can inspect the custom code I wrote [in the gt4carp repository TODO: good link](https://git.veitheller.de/carpentry/gt4carp)."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:06:15.752492+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:07:40.565555+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "tJmV+I+dDQC/nrmHA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "While I understand that this is a rather terse “figure it out yourself”, I dont know the ins and outs of the LanguageLink protocol well enough to assist you any more—precisely because I took the effort of side-stepping the issue entirely. Hopefully you can too!"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:05.418793+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:05.418793+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "Building a LanguageLink server"
},
"uid" : {
"__type" : "uuid",
"uuid" : "e4a14bbb-8f9d-0d00-bf7b-383c03c131a4"
}
}

View File

@@ -0,0 +1,261 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:28:18.00762+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:30:10.327276+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "xNZI/4+dDQC/o+CfA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Finally, finally we get to have a snippet type that actually knows how to execute code!"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:30:14.076728+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:31:02.274958+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "t3BjTpCdDQCAUTe6A8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "To make that happen, we will need an application strategy. Building one should be fairly straightforward, since it mostly holds onto your LanguageLink application and builds new ones if needed."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:31:19.494771+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:32:06.868833+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "E6NbUZCdDQCAU8nsA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "More interesting will be your coder model, which is responsible for taking source code from an application, handing it over to LanguageLink, and displaying the result. As such, it is the main link between the IDE and the execution engine."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:32:07.688865+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:34:29.49505+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "ypstVZCdDQCAYOo/A8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "In the section [[What now?]] I already showcased the method that is most central to that process: `bindAndExecute:`. In my case, {{gtMethod:GtCarpCoderModel>>#bindAndExecute:|expanded}} is the final result. A quick refresher:"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:34:40.493148+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:36:37.301362+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "WALsXZCdDQCBUGyRA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "The method will take in a source string directly from coder and send it off to the evaluator handled by the LanguageLink application. Before that happens, though, it will most likely add some funky code around the snippet to capture the statement as a variable if possible, to allow for better interaction with GT."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:36:42.952545+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:37:23.855402+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "R7ljZZCdDQCBUlkLA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "It might be more useful for you to start with a trimmed-down version of this method that doesnt do anything with the bindings and just hands over the source string as-is. To harness the full power of interacting with G"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:06.046507+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:06.046507+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "Hooking up your LanguageLink server"
},
"uid" : {
"__type" : "uuid",
"uuid" : "e53a48ff-8f9d-0d00-bfa2-217603c131a4"
}
}

View File

@@ -0,0 +1,261 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:28:18.00762+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:30:10.327276+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "xNZI/4+dDQC/o+CfA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Finally, finally we get to have a snippet type that actually knows how to execute code!"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:30:14.076728+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:31:02.274958+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "t3BjTpCdDQCAUTe6A8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "To make that happen, we will need an application strategy. Building one should be fairly straightforward, since it mostly holds onto your LanguageLink application and builds new ones if needed."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:31:19.494771+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:32:06.868833+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "E6NbUZCdDQCAU8nsA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "More interesting will be your coder model, which is responsible for taking source code from an application, handing it over to LanguageLink, and displaying the result. As such, it is the main link between the IDE and the execution engine."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:32:07.688865+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:34:29.49505+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "ypstVZCdDQCAYOo/A8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "In the section [[What now?]] I already showcased the method that is most central to that process: `bindAndExecute:`. In my case, {{gtMethod:GtCarpCoderModel>>#bindAndExecute:|expanded}} is the final result. A quick refresher:"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:34:40.493148+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:36:37.301362+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "WALsXZCdDQCBUGyRA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "The method will take in a source string directly from coder and send it off to the evaluator handled by the LanguageLink application. Before that happens, though, it will most likely add some funky code around the snippet to capture the statement as a variable if possible, to allow for better interaction with GT."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:36:42.952545+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:37:38.760779+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "R7ljZZCdDQCBUlkLA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "It might be more useful for you to start with a trimmed-down version of this method that doesnt do anything with the bindings and just hands over the source string as-is. To harness the full power of interacting with GT, however, we will need to send variables and values back and forth sooner or later."
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:06.046507+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:08:06.046507+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "Hooking up your LanguageLink server"
},
"uid" : {
"__type" : "uuid",
"uuid" : "e53a48ff-8f9d-0d00-bfa2-217603c131a4"
}
}

View File

@@ -0,0 +1,224 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:08.96254+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:10.799078+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "6bymapCdDQCBW13UA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "You made it!"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:12.929099+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:56.257815+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "IW3tapCdDQCBXcd8A8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "If you read this booklet linearly from start to finish and followed along with your own implementation, you should now be able to execute code in custom Lepiter snippets! Exciting indeed!"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:59.504959+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:40:09.625312+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "4R2abZCdDQCBX8vQA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Now, of course, the fun doesnt stop here. For full interactivity, we might need to (de)serialize values in an almost seamless manner, like JSLink does. To do that, we will have to make GT understand our language semantically rather than just syntactically."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:40:10.264658+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:41:08.513478+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "kHzzcZCdDQCBYawWA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "We could also start using GTs powers to visualize things about our codebase or to generate code, or we might want to create a custom IDE. Some of these fun adventures you will have to embark on on your own, but if you want some inspiration, the [[Bonus Chapters]] might hold some interest to you."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:41:12.090085+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:41:24.342689+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "nEKhdZCdDQCBgxEjA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "I hope you enjoyed our little journey, congratulate you to your new po"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:07.35881+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:07.35881+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "Fin"
},
"uid" : {
"__type" : "uuid",
"uuid" : "1d13a66a-909d-0d00-815a-f07803c131a4"
}
}

View File

@@ -0,0 +1,224 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:08.96254+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:10.799078+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "6bymapCdDQCBW13UA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "You made it!"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:12.929099+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:56.257815+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "IW3tapCdDQCBXcd8A8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "If you read this booklet linearly from start to finish and followed along with your own implementation, you should now be able to execute code in custom Lepiter snippets! Exciting indeed!"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:59.504959+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:40:09.625312+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "4R2abZCdDQCBX8vQA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Now, of course, the fun doesnt stop here. For full interactivity, we might need to (de)serialize values in an almost seamless manner, like JSLink does. To do that, we will have to make GT understand our language semantically rather than just syntactically."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:40:10.264658+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:41:08.513478+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "kHzzcZCdDQCBYawWA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "We could also start using GTs powers to visualize things about our codebase or to generate code, or we might want to create a custom IDE. Some of these fun adventures you will have to embark on on your own, but if you want some inspiration, the [[Bonus Chapters]] might hold some interest to you."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:41:12.090085+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:41:41.069403+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "nEKhdZCdDQCBgxEjA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "I hope you enjoyed our little journey and congratulate you to your new powers! See you around."
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:07.35881+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T18:38:07.35881+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "Fin"
},
"uid" : {
"__type" : "uuid",
"uuid" : "1d13a66a-909d-0d00-815a-f07803c131a4"
}
}

View File

@@ -0,0 +1,224 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:47.434396+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:50:11.430885+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "YVM4u4+dDQC/eTezA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Building a LanguageLink client is easy, but not necessarily simple, since it involves writing a lot of mostly glue code."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:50:15.711236+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:52:49.226165+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "suJsv4+dDQC/h6EvA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "As an entry-point, you will have to write a {{gtClass:LanguageLinkApplication}}. The (very spartan) one for Carp is {{gtClass:CarpApplication}}. Writing the application will give you a lay of the land, since its the central piece of infrastructure that holds on to all the rest."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:52:50.001285+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:53:48.39118+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "/4qmyI+dDQC/i6IPA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "In the Carp application, I tried to use stock classes from LanguageLink wherever possible. Only when that didnt work did I add classes. I also took inspiration from {{gtClass:JSLinkApplication}}, since it was there and seemed to provide rich functionality."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:53:50.150304+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:57:15.031561+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "hy01zI+dDQC/j6rJA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "In total, all the classes that needed filling in were {{gtClass:CarpPostMortemDebugger}} (used in: {{gtMethod:CarpApplication>>debuggerClientFor:}}), {{gtClass:CarpExecutionHandler}} (used in {{gtMethod:CarpApplication>>#initializeHandlers}}), and all the classes in {{gtMethod:LanguageLinkSettings class>>carpDefaultSettings|expanded}} prefixed with `Carp`:"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:57:33.45648+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:59:17.862655+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "sPXB2I+dDQC/k6TTA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Implementing and understanding all of these classes might seem like a daunting task, and in many ways it is. But implementing most of these classes is simple and doesnt at first require a thorough understanding of the system, at least that was the case for me. This means that you can just browse the existing implementors of any specific piece of infrastructure and “compare notes”. This approach got me f"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:04.110462+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:04.110462+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "Building a LanguageLink client"
},
"uid" : {
"__type" : "uuid",
"uuid" : "3aab37bb-8f9d-0d00-bf78-07ff03c131a4"
}
}

View File

@@ -0,0 +1,224 @@
{
"__schema" : "4.1",
"__type" : "page",
"children" : {
"__type" : "snippets",
"items" : [
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:47.434396+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:50:11.430885+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "YVM4u4+dDQC/eTezA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Building a LanguageLink client is easy, but not necessarily simple, since it involves writing a lot of mostly glue code."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:50:15.711236+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:52:49.226165+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "suJsv4+dDQC/h6EvA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "As an entry-point, you will have to write a {{gtClass:LanguageLinkApplication}}. The (very spartan) one for Carp is {{gtClass:CarpApplication}}. Writing the application will give you a lay of the land, since its the central piece of infrastructure that holds on to all the rest."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:52:50.001285+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:53:48.39118+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "/4qmyI+dDQC/i6IPA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "In the Carp application, I tried to use stock classes from LanguageLink wherever possible. Only when that didnt work did I add classes. I also took inspiration from {{gtClass:JSLinkApplication}}, since it was there and seemed to provide rich functionality."
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:53:50.150304+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:57:15.031561+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "hy01zI+dDQC/j6rJA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "In total, all the classes that needed filling in were {{gtClass:CarpPostMortemDebugger}} (used in: {{gtMethod:CarpApplication>>debuggerClientFor:}}), {{gtClass:CarpExecutionHandler}} (used in {{gtMethod:CarpApplication>>#initializeHandlers}}), and all the classes in {{gtMethod:LanguageLinkSettings class>>carpDefaultSettings|expanded}} prefixed with `Carp`:"
},
{
"__type" : "textSnippet",
"children" : {
"__type" : "snippets",
"items" : [ ]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:57:33.45648+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:59:36.36081+02:00"
}
},
"uid" : {
"__type" : "uid",
"uidString" : "sPXB2I+dDQC/k6TTA8ExpA=="
},
"paragraphStyle" : {
"__type" : "textStyle"
},
"string" : "Implementing and understanding all of these classes might seem like a daunting task, and in many ways it is. But implementing most of these classes is simple and doesnt at first require a thorough understanding of the system, at least that was the case for me. This means that you can just browse the existing implementors of any specific piece of infrastructure and “compare notes”. This approach got me far enough to build a first version (with a little bit of added debugging), and it might get you there too!"
}
]
},
"createEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"createTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:04.110462+02:00"
}
},
"editEmail" : {
"__type" : "email",
"emailString" : "<unknown>"
},
"editTime" : {
"__type" : "time",
"time" : {
"__type" : "dateAndTime",
"dateAndTimeString" : "2022-06-11T17:49:04.110462+02:00"
}
},
"pageType" : {
"__type" : "namedPage",
"title" : "Building a LanguageLink client"
},
"uid" : {
"__type" : "uuid",
"uuid" : "3aab37bb-8f9d-0d00-bf78-07ff03c131a4"
}
}

View File

@@ -2,5 +2,5 @@
"uuid" : "de53e067-3c99-0d00-9999-34310ea9f69b",
"tableOfContents" : "98eic2d1mangtosf26n3aq420",
"schema" : "4.1",
"databaseName" : "Adding a Language to the Glamorous Toolkit"
"databaseName" : "Adding a Language to Glamorous Toolkit"
}

View File

@@ -11,26 +11,27 @@ Class {
#category : #'Carp-Processes'
}
{ #category : #accessing }
CarpProcess class >> program [
^ 'carp'
]
{ #category : #accessing }
CarpProcess class >> resolveCarpPath [
| proc |
proc := GtSubprocessWithInMemoryOutput new
command: 'which';
arguments: { 'carp' }.
arguments: { self program}.
CarpPlatform subProcessEnvironmentDictionary keysAndValuesDo: [ :key :value |
proc environmentAt: key put: value ].
proc runAndWait.
(#(0 1) includes: proc exitCode) ifFalse:
[ self error: 'Unable to request carp location' ].
[ self error: 'Unable to request', self program, ' location' ].
^ proc stdout trim asFileReference
]
{ #category : #accessing }
CarpProcess class >> resolveNodejsPath [
]
{ #category : #accessing }
CarpProcess class >> serverPath [
^ CarpPath
@@ -89,12 +90,17 @@ CarpProcess >> processArguments [
self settings serverDebugMode ifTrue:
[ args add: '--inspect' ].
args
add: (self workingDirectory / 'src/languagelink.carp') resolve fullName;
add: (self workingDirectory / self programFile) resolve fullName;
add: self settings serverSocketAddress port asString;
add: self settings clientSocketAddress port asString.
^ args
]
{ #category : #accessing }
CarpProcess >> programFile [
^ 'src/languagelink.carp'
]
{ #category : #accessing }
CarpProcess >> serverPath [
| fileReference |

View File

@@ -0,0 +1,15 @@
Class {
#name : #CarpPythonProcess,
#superclass : #CarpProcess,
#category : #'Carp-Processes'
}
{ #category : #accessing }
CarpPythonProcess class >> program [
^ 'python'
]
{ #category : #accessing }
CarpPythonProcess >> programFile [
^ 'src/languagelink.py'
]

View File

@@ -9,7 +9,7 @@ LanguageLinkSettings class >> carpDefaultSettings [
serverSocketAddress: (LanguageLinkSocketAddress
ipOrName: 'localhost' port: (9900 + 99 atRandom));
messageBrokerStrategy: LanguageLinkHttpMessageBroker;
serverProcessClass: CarpProcess;
serverProcessClass: CarpPythonProcess;
platform: CarpPlatform new;
commandFactoryClass: CarpCommandFactory;
commandClass: LanguageLinkCommand;