Last active
February 20, 2021 04:12
-
-
Save inariksit/76e34b5746ab1d13ec7dcd5cf0b7eb19 to your computer and use it in GitHub Desktop.
Small example of a formal language in GF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Abstract syntax for a fragment of a proramming language. | |
-- Only class definition, to keep the example small. | |
abstract MyOOP = { | |
flags startcat = Class ; | |
cat | |
Class ; -- class ClassName : { [Field] } | |
Field ; -- field_name : BuiltinType | |
[Field]{0} ; | |
BuiltinType ; | |
fun | |
ClassDef : String -> [Field] -> Class ; | |
MkField : String -> BuiltinType -> Field ; | |
BoolType, StringType : BuiltinType ; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- Concrete syntax for a programming language. | |
-- Example: class Business = { is_legal : Boolean } ; | |
concrete MyOOPCnc of MyOOP = { | |
lincat | |
[Field] = {s : Str ; isEmpty : IsEmpty} ; | |
param | |
IsEmpty = Empty | NonEmpty ; | |
lin | |
-- : String -> [Field] -> Class ; | |
ClassDef name fields = { | |
s = "class" ++ name.s ++ | |
case fields.isEmpty of { | |
Empty => fields.s ; | |
NonEmpty => "= {" ++ fields.s ++ "}" | |
} ++ ";" | |
} ; | |
-- : String -> BuiltinType -> Field ; | |
MkField name type = {s = name.s ++ ":" ++ type.s} ; | |
-- These funs are automatically generated from cat [Field]{0} ; | |
-- : [Field] | |
BaseField = {s = [] ; isEmpty = Empty} ; | |
-- : Field -> [Field] -> [Field] | |
ConsField f fs = | |
let sep : Str = case fs.isEmpty of { | |
Empty => [] ; | |
NonEmpty => ";" } ; | |
in {s = f.s ++ sep ++ fs.s ; isEmpty = NonEmpty} ; | |
-- : BuiltinType ; | |
BoolType = {s = "Boolean"} ; | |
StringType = {s = "String"} ; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- English concrete syntax. | |
-- Example: Business is a class with a Boolean field is_legal | |
concrete MyOOPEng of MyOOP = open SyntaxEng, (P=ParadigmsEng), SymbolicEng in { | |
lincat | |
Class = S ; | |
Field = LinField ; -- name : NP ; type : LinBuiltin | |
[Field] = { | |
s : ListNP ; | |
size : Size ; | |
firstField : LinField ; -- If only 1 field, use compact description | |
} ; | |
BuiltinType = LinBuiltin ; -- Two ways to express type: | |
-- AP: Boolean (field foo) | |
-- Adv: (field foo) of type Boolean | |
param | |
Size = Zero | One | Many ; -- Size of list | |
----------- | |
-- Class -- | |
----------- | |
lin | |
-- : String -> [Field] -> Class ; | |
ClassDef name fields = | |
let classname : NP = symb name ; | |
with_fields : Adv = case fields.size of { | |
Zero => mkAdv with_Prep (mkNP noPl_Det field_N) ; -- with no fields | |
One => withField fields.firstField ; -- with a <type> field <name> | |
Many => withField fields.s -- with fields <name1 of type1, …> | |
} ; | |
description : NP = mkNP a_Det (mkCN class_N with_fields) | |
in mkS (mkCl classname description) ; | |
oper | |
withField = overload { | |
withField : LinField -> Adv = \fld -> -- (class) with a Boolean field is_legal | |
let boolean_AP : AP = fld.type.ap ; | |
is_legal_NP : NP = fld.name | |
in mkAdv with_Prep (mkNP a_Det | |
(mkCN boolean_AP | |
(mkCN field_N is_legal_NP))) ; | |
withField : [NP] -> Adv = \fields -> -- (class) with fields <is_legal of type Boolean, …> | |
mkAdv with_Prep (mkNP aPl_Det | |
(mkCN field_N | |
(mkNP and_Conj fields))) | |
} ; | |
-- Lexicon | |
class_N : N = P.mkN "class" ; | |
field_N : N = P.mkN "field" ; | |
noPl_Det : Det = mkDet no_Quant pluralNum ; | |
------------ | |
-- Fields -- | |
------------ | |
lin | |
-- : String -> BuiltinType -> Field ; | |
MkField name type = { | |
name = symb name ; | |
type = type | |
} ; | |
-- : [Field] | |
BaseField = dummyListField ; | |
-- : Field -> [Field] -> [Field] | |
ConsField f fs = | |
case fs.size of { | |
Zero => fs ** { -- s is still just a dummy list, not used in ClassDef! | |
firstField = f ; -- put f into firstField | |
size = One -- increase size | |
} ; | |
One => fs ** { | |
s = mkListField f fs.firstField ; -- construct first actual list from f and fs.firstField | |
size = Many | |
} ; | |
Many => fs ** {s = mkListField f fs.s} -- add the new field to the existing list | |
} ; | |
oper | |
LinField : Type = { | |
name : NP ; | |
type : LinBuiltin | |
} ; | |
ofType : LinField -> NP = \fld -> mkNP fld.name fld.type.adv ; | |
mkListField = overload { | |
mkListField : LinField -> LinField -> ListNP = \f1,f2 -> | |
mkListNP (ofType f1) (ofType f2) ; | |
mkListField : LinField -> ListNP -> ListNP = \f,fs -> | |
mkListNP (ofType f) fs | |
} ; | |
-- Even empty lists must contain some ListNP, some NP etc. | |
-- None of these are ever used in ClassDef. | |
-- The important info is size = Zero. That tells ClassDef to output "a class with no fields". | |
dummyListField = { | |
s = mkListNP nothing_NP nothing_NP ; | |
firstField = { | |
name = nothing_NP ; | |
type = {ap = mkAP (P.mkA "empty") ; adv = P.mkAdv "nothing"} | |
} ; | |
size = Zero | |
} ; | |
-------------------- | |
-- Builtin types -- | |
-------------------- | |
lin | |
BoolType = mkType "Boolean" ; | |
StringType = mkType "String" ; | |
oper | |
LinBuiltin : Type = {ap : AP ; adv : Adv} ; | |
mkType : Str -> LinBuiltin = \str -> { | |
ap = mkAP (P.mkA str) ; | |
adv = mkAdv (P.mkPrep "of type") (mkNP (P.mkPN str)) | |
} ; | |
-- To make BuiltinTypes print out nicely in the GF shell, we use a linref. | |
-- See explanation in https://inariksit.github.io/gf/2018/08/28/gf-gotchas.html#linref | |
linref | |
BuiltinType = \bt -> (mkUtt bt.ap).s ; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment