Skip to content

Commit 36f027b

Browse files
authored
Merge pull request #44206 from ballerina-platform/natural-expr-update
Add the natural langlib and update the natural expression
2 parents 0462ef7 + 9e0e5a4 commit 36f027b

File tree

710 files changed

+8501
-181
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

710 files changed

+8501
-181
lines changed

bvm/ballerina-rt/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ dependencies {
4242
dist project(path: ':ballerina-lang:future', configuration: 'distributionBirJar')
4343
dist project(path: ':ballerina-lang:integer', configuration: 'distributionBirJar')
4444
dist project(path: ':ballerina-lang:map', configuration: 'distributionBirJar')
45+
dist project(path: ':ballerina-lang:natural', configuration: 'distributionBirJar')
4546
dist project(path: ':ballerina-lang:object', configuration: 'distributionBirJar')
4647
dist project(path: ':ballerina-lang:stream', configuration: 'distributionBirJar')
4748
dist project(path: ':ballerina-lang:table', configuration: 'distributionBirJar')
@@ -66,6 +67,7 @@ dependencies {
6667
dist project(':ballerina-lang:future')
6768
dist project(':ballerina-lang:integer')
6869
dist project(':ballerina-lang:map')
70+
dist project(':ballerina-lang:natural')
6971
dist project(':ballerina-lang:object')
7072
dist project(':ballerina-lang:stream')
7173
dist project(':ballerina-lang:table')

compiler/ballerina-lang/src/main/java/io/ballerina/projects/Bootstrap.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import static org.ballerinalang.model.elements.PackageID.INTERNAL;
4545
import static org.ballerinalang.model.elements.PackageID.JAVA;
4646
import static org.ballerinalang.model.elements.PackageID.MAP;
47+
import static org.ballerinalang.model.elements.PackageID.NATURAL;
4748
import static org.ballerinalang.model.elements.PackageID.OBJECT;
4849
import static org.ballerinalang.model.elements.PackageID.QUERY;
4950
import static org.ballerinalang.model.elements.PackageID.REGEXP;
@@ -194,6 +195,8 @@ public void loadLangLibSymbols(CompilerContext compilerContext) {
194195
symbolTable.langObjectModuleSymbol = loadLangLibFromBala(OBJECT, compilerContext);
195196
symResolver.loadRawTemplateType();
196197
symResolver.bootstrapIterableType();
198+
symbolTable.langNaturalModuleSymbol = loadLangLibFromBala(NATURAL, compilerContext);
199+
symResolver.loadNaturalGeneratorType();
197200
symbolTable.langStreamModuleSymbol = loadLangLibFromBala(STREAM, compilerContext);
198201
symbolTable.langTableModuleSymbol = loadLangLibFromBala(TABLE, compilerContext);
199202
symbolTable.langRegexpModuleSymbol = loadLangLibFromBala(REGEXP, compilerContext);

compiler/ballerina-lang/src/main/java/io/ballerina/projects/internal/NaturalProgrammingImportAnalyzer.java

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,18 @@
2020

2121
import io.ballerina.compiler.syntax.tree.ExternalFunctionBodyNode;
2222
import io.ballerina.compiler.syntax.tree.FunctionDefinitionNode;
23+
import io.ballerina.compiler.syntax.tree.IdentifierToken;
24+
import io.ballerina.compiler.syntax.tree.ImportDeclarationNode;
25+
import io.ballerina.compiler.syntax.tree.ImportOrgNameNode;
26+
import io.ballerina.compiler.syntax.tree.ImportPrefixNode;
2327
import io.ballerina.compiler.syntax.tree.ModulePartNode;
2428
import io.ballerina.compiler.syntax.tree.NaturalExpressionNode;
2529
import io.ballerina.compiler.syntax.tree.Node;
2630
import io.ballerina.compiler.syntax.tree.NodeVisitor;
27-
import io.ballerina.compiler.syntax.tree.SimpleNameReferenceNode;
31+
import io.ballerina.compiler.syntax.tree.QualifiedNameReferenceNode;
32+
import io.ballerina.compiler.syntax.tree.SeparatedNodeList;
33+
34+
import java.util.Optional;
2835

2936
/**
3037
* Check and add an import for the natural programming module if there is a natural expression.
@@ -34,15 +41,51 @@
3441
public class NaturalProgrammingImportAnalyzer extends NodeVisitor {
3542

3643
private boolean shouldImportNaturalProgrammingModule = false;
44+
private Optional<String> naturalLangLibPrefix = Optional.of(NATURAL_WITH_QUOTE);
45+
46+
private static final String BALLERINA = "ballerina";
47+
private static final String LANG = "lang";
48+
private static final String NATURAL = "natural";
49+
private static final String NATURAL_WITH_QUOTE = "'natural";
3750
private static final String CODE_ANNOTATION = "code";
3851

3952
public boolean shouldImportNaturalProgrammingModule(ModulePartNode modulePartNode) {
4053
modulePartNode.accept(this);
4154
return this.shouldImportNaturalProgrammingModule;
4255
}
4356

57+
@Override
58+
public void visit(ImportDeclarationNode importDeclarationNode) {
59+
Optional<String> prefixStr = Optional.empty();
60+
boolean isNaturalPrefix = false;
61+
62+
Optional<ImportPrefixNode> prefix = importDeclarationNode.prefix();
63+
if (prefix.isPresent()) {
64+
String prefixValue = prefix.get().prefix().text();
65+
if (NATURAL_WITH_QUOTE.equals(prefixValue)) {
66+
isNaturalPrefix = true;
67+
}
68+
prefixStr = Optional.of(prefixValue);
69+
}
70+
71+
if (isNaturalLangLibImport(importDeclarationNode)) {
72+
if (prefixStr.isPresent() && !isNaturalPrefix) {
73+
naturalLangLibPrefix = prefixStr;
74+
}
75+
return;
76+
}
77+
78+
if (isNaturalPrefix &&
79+
naturalLangLibPrefix.isPresent() &&
80+
NATURAL_WITH_QUOTE.equals(naturalLangLibPrefix.get())) {
81+
naturalLangLibPrefix = Optional.empty();
82+
}
83+
}
84+
4485
@Override
4586
public void visit(NaturalExpressionNode naturalExpressionNode) {
87+
// For now, we will import the np module for runtime natural expressions also, to add the schema annotation
88+
// for expected type of natural expressions.
4689
this.shouldImportNaturalProgrammingModule = true;
4790
}
4891

@@ -65,10 +108,16 @@ private boolean isExternalFunctionWithCodeAnnotation(FunctionDefinitionNode func
65108
return false;
66109
}
67110

111+
if (naturalLangLibPrefix.isEmpty()) {
112+
return false;
113+
}
114+
68115
return externalFunctionBodyNode.annotations().stream()
69116
.anyMatch(annotation ->
70-
annotation.annotReference() instanceof SimpleNameReferenceNode annotReference &&
71-
CODE_ANNOTATION.equals(annotReference.name().text()));
117+
annotation.annotReference() instanceof QualifiedNameReferenceNode qualifiedNameReferenceNode &&
118+
isNaturalPrefix(naturalLangLibPrefix.get()) &&
119+
isNaturalPrefix(qualifiedNameReferenceNode.modulePrefix().text()) &&
120+
CODE_ANNOTATION.equals(qualifiedNameReferenceNode.identifier().text()));
72121
}
73122

74123
@Override
@@ -78,4 +127,20 @@ protected void visitSyntaxNode(Node node) {
78127
}
79128
super.visitSyntaxNode(node);
80129
}
130+
131+
private boolean isNaturalLangLibImport(ImportDeclarationNode importDeclarationNode) {
132+
Optional<ImportOrgNameNode> importOrgNameNode = importDeclarationNode.orgName();
133+
if (importOrgNameNode.isEmpty() || !BALLERINA.equals(importOrgNameNode.get().orgName().text())) {
134+
return false;
135+
}
136+
137+
SeparatedNodeList<IdentifierToken> moduleName = importDeclarationNode.moduleName();
138+
return moduleName.size() == 2 &&
139+
moduleName.get(0).text().equals(LANG) &&
140+
moduleName.get(1).text().equals(NATURAL_WITH_QUOTE);
141+
}
142+
143+
private boolean isNaturalPrefix(String prefix) {
144+
return NATURAL.equals(prefix) || NATURAL_WITH_QUOTE.equals(prefix);
145+
}
81146
}

compiler/ballerina-lang/src/main/java/org/ballerinalang/model/elements/PackageID.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ public class PackageID {
6464
Lists.of(Names.LANG, Names.INT), DEFAULT_VERSION);
6565
public static final PackageID MAP = new PackageID(Names.BALLERINA_ORG,
6666
Lists.of(Names.LANG, Names.MAP), DEFAULT_VERSION);
67+
public static final PackageID NATURAL = new PackageID(Names.BALLERINA_ORG,
68+
Lists.of(Names.LANG, Names.NATURAL), DEFAULT_VERSION);
6769
public static final PackageID OBJECT = new PackageID(Names.BALLERINA_ORG,
6870
Lists.of(Names.LANG, Names.OBJECT), DEFAULT_VERSION);
6971
public static final PackageID STREAM = new PackageID(Names.BALLERINA_ORG,

compiler/ballerina-lang/src/main/java/org/ballerinalang/util/diagnostic/DiagnosticErrorCode.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,10 @@ public enum DiagnosticErrorCode implements DiagnosticCode {
827827
CONST_NATURAL_EXPR_CAN_HAVE_ONLY_CONST_EXPR_INSERTION(
828828
"BCE4073", "const.natural.expr.can.have.only.const.expr.insertion"),
829829
EXPECTED_TYPE_FOR_CONST_NATURAL_EXPR_MUST_BE_A_SUBTYPE_OF_ANYDATA(
830-
"BCE4074", "expected.type.for.const.natural.expr.must.be.a.subtype.of.anydata")
830+
"BCE4074", "expected.type.for.const.natural.expr.must.be.a.subtype.of.anydata"),
831+
EXPECTED_A_SINGLE_ARG_OF_TYPE_GENERATOR_IN_A_NATURAL_EXPR(
832+
"BCE4075", "expected.a.single.arg.of.type.generator.in.a.natural.expr"),
833+
EXPECTED_NO_ARGS_IN_A_CONST_NATURAL_EXPR("BCE4076", "expected.no.args.in.a.const.natural.expr")
831834
;
832835

833836
private final String diagnosticId;

compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/ASTBuilderUtil.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
import org.wso2.ballerinalang.compiler.tree.expressions.BLangLiteral;
7474
import org.wso2.ballerinalang.compiler.tree.expressions.BLangMatchGuard;
7575
import org.wso2.ballerinalang.compiler.tree.expressions.BLangNamedArgsExpression;
76+
import org.wso2.ballerinalang.compiler.tree.expressions.BLangRawTemplateLiteral;
7677
import org.wso2.ballerinalang.compiler.tree.expressions.BLangReCharSet;
7778
import org.wso2.ballerinalang.compiler.tree.expressions.BLangReFlagExpression;
7879
import org.wso2.ballerinalang.compiler.tree.expressions.BLangReFlagsOnOff;
@@ -1089,4 +1090,14 @@ static BLangReFlagsOnOff createEmptyFlagOnOff(Location pos, BType exprType, BTyp
10891090
flagExpr.setBType(exprType);
10901091
return flagExpr;
10911092
}
1093+
1094+
static BLangRawTemplateLiteral createRawTemplateExpression(Location location, BType type,
1095+
List<BLangLiteral> strings, List<BLangExpression> insertions) {
1096+
BLangRawTemplateLiteral rawTemplateExpr = (BLangRawTemplateLiteral) TreeBuilder.createRawTemplateLiteralNode();
1097+
rawTemplateExpr.pos = location;
1098+
rawTemplateExpr.strings = strings;
1099+
rawTemplateExpr.insertions = insertions;
1100+
rawTemplateExpr.setBType(type);
1101+
return rawTemplateExpr;
1102+
}
10921103
}

compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/desugar/Desugar.java

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
import org.wso2.ballerinalang.compiler.tree.expressions.BLangLiteral;
176176
import org.wso2.ballerinalang.compiler.tree.expressions.BLangMultipleWorkerReceive;
177177
import org.wso2.ballerinalang.compiler.tree.expressions.BLangNamedArgsExpression;
178+
import org.wso2.ballerinalang.compiler.tree.expressions.BLangNaturalExpression;
178179
import org.wso2.ballerinalang.compiler.tree.expressions.BLangObjectConstructorExpression;
179180
import org.wso2.ballerinalang.compiler.tree.expressions.BLangQueryAction;
180181
import org.wso2.ballerinalang.compiler.tree.expressions.BLangQueryExpr;
@@ -376,6 +377,8 @@ public class Desugar extends BLangNodeVisitor {
376377
private static final String HAS_KEY = "hasKey";
377378
private static final String CREATE_RECORD_VALUE = "createRecordFromMap";
378379
private static final String CHANNEL_AUTO_CLOSE_FUNC_NAME = "autoClose";
380+
private static final String GENERATE = "generate";
381+
private static final String ESCAPED_BACKTICK = "\"`\"";
379382

380383
public static final String XML_INTERNAL_CHILDREN = "children";
381384
public static final String XML_MAP = "map";
@@ -9171,6 +9174,30 @@ public void visit(BLangReFlagsOnOff reFlagsOnOff) {
91719174
result = reFlagsOnOff;
91729175
}
91739176

9177+
@Override
9178+
public void visit(BLangNaturalExpression naturalExpression) {
9179+
if (naturalExpression.isConstExpr) {
9180+
// Shouldn't get here
9181+
throw new IllegalStateException("'const' natural expression should be handled by the implementation");
9182+
}
9183+
9184+
Location pos = naturalExpression.pos;
9185+
String varName = anonModelHelper.getNextNaturalGeneratorVariableName(env.enclPkg.packageID);
9186+
9187+
BLangSimpleVariableDef generatorVariableDef =
9188+
createGeneratorVariableDefinition(naturalExpression, varName, pos);
9189+
BType bType = naturalExpression.getBType();
9190+
BLangInvocation generatorGenerateCall = createGeneratorGenerateCall(
9191+
pos, generatorVariableDef, naturalExpression, bType);
9192+
9193+
BLangBlockStmt blockStmt = createBlockStmt(pos);
9194+
blockStmt.addStatement(generatorVariableDef);
9195+
9196+
BLangStatementExpression statementExpression = createStatementExpression(blockStmt, generatorGenerateCall);
9197+
statementExpression.setBType(bType);
9198+
result = rewrite(statementExpression, env);
9199+
}
9200+
91749201
// private functions
91759202

91769203
// Foreach desugar helper method.
@@ -9211,7 +9238,7 @@ BLangInvocation createIteratorNextInvocation(Location pos, BVarSymbol iteratorSy
92119238
BLangIdentifier nextIdentifier = ASTBuilderUtil.createIdentifier(pos, "next");
92129239
BLangSimpleVarRef iteratorReferenceInNext = ASTBuilderUtil.createVariableRef(pos, iteratorSymbol);
92139240
BInvokableSymbol nextFuncSymbol =
9214-
getNextFunc((BObjectType) Types.getImpliedType(iteratorSymbol.type)).symbol;
9241+
getObjectMethod((BObjectType) Types.getImpliedType(iteratorSymbol.type), "next").symbol;
92159242
BLangInvocation nextInvocation = (BLangInvocation) TreeBuilder.createInvocationNode();
92169243
nextInvocation.pos = pos;
92179244
nextInvocation.name = nextIdentifier;
@@ -9223,10 +9250,10 @@ BLangInvocation createIteratorNextInvocation(Location pos, BVarSymbol iteratorSy
92239250
return nextInvocation;
92249251
}
92259252

9226-
private BAttachedFunction getNextFunc(BObjectType iteratorType) {
9227-
BObjectTypeSymbol iteratorSymbol = (BObjectTypeSymbol) iteratorType.tsymbol;
9253+
private BAttachedFunction getObjectMethod(BObjectType objectType, String methodName) {
9254+
BObjectTypeSymbol iteratorSymbol = (BObjectTypeSymbol) objectType.tsymbol;
92289255
for (BAttachedFunction bAttachedFunction : iteratorSymbol.attachedFuncs) {
9229-
if (bAttachedFunction.funcName.value.equals("next")) {
9256+
if (bAttachedFunction.funcName.value.equals(methodName)) {
92309257
return bAttachedFunction;
92319258
}
92329259
}
@@ -11008,4 +11035,83 @@ private static void markAndAddPossibleClosureVarsToArrowFunction(BLangArrowFunct
1100811035
private void clearGlobalVariables() {
1100911036
this.typedescList = null;
1101011037
}
11038+
11039+
private BLangSimpleVariableDef createGeneratorVariableDefinition(BLangNaturalExpression naturalExpression,
11040+
String varName, Location pos) {
11041+
BVarSymbol generatorVarSymbol = new BVarSymbol(0, Names.fromString(varName), env.scope.owner.pkgID,
11042+
symTable.naturalGeneratorType, this.env.scope.owner, pos, VIRTUAL);
11043+
BLangSimpleVariable generatorVariable = ASTBuilderUtil.createVariable(pos,
11044+
varName, symTable.naturalGeneratorType, naturalExpression.arguments.getFirst(), generatorVarSymbol);
11045+
return ASTBuilderUtil.createVariableDef(pos, generatorVariable);
11046+
}
11047+
11048+
private BLangInvocation createGeneratorGenerateCall(Location pos, BLangSimpleVariableDef generatorVariableDef,
11049+
BLangNaturalExpression naturalExpression, BType exprType) {
11050+
BType nonErrorType = types.getSafeType(exprType, false, true);
11051+
BType typedescType = new BTypedescType(symTable.typeEnv(), nonErrorType, symTable.typeDesc.tsymbol);
11052+
11053+
BVarSymbol generatorVarSymbol = generatorVariableDef.var.symbol;
11054+
BLangSimpleVarRef generatorVarRef = ASTBuilderUtil.createVariableRef(pos, generatorVarSymbol);
11055+
BLangIdentifier generateIdentifier = ASTBuilderUtil.createIdentifier(pos, GENERATE);
11056+
BInvokableSymbol generateMethodSymbol = getObjectMethod(
11057+
(BObjectType) Types.getImpliedType(symTable.naturalGeneratorType), GENERATE).symbol;
11058+
BLangInvocation generateCall = (BLangInvocation) TreeBuilder.createInvocationNode();
11059+
generateCall.pos = pos;
11060+
generateCall.name = generateIdentifier;
11061+
generateCall.expr = generatorVarRef;
11062+
generateCall.requiredArgs = Lists.of(
11063+
createPromptRawTemplate(naturalExpression),
11064+
ASTBuilderUtil.createTypedescExpr(pos, typedescType, nonErrorType)
11065+
);
11066+
generateCall.argExprs = generateCall.requiredArgs;
11067+
generateCall.symbol = generateMethodSymbol;
11068+
generateCall.setBType(exprType);
11069+
return generateCall;
11070+
}
11071+
11072+
private BLangRawTemplateLiteral createPromptRawTemplate(BLangNaturalExpression naturalExpression) {
11073+
Location pos = naturalExpression.pos;
11074+
List<BLangLiteral> updatedStrings = new ArrayList<>();
11075+
List<BLangExpression> updatedInsertions = new ArrayList<>();
11076+
11077+
List<BLangLiteral> strings = naturalExpression.strings;
11078+
List<BLangExpression> insertions = naturalExpression.insertions;
11079+
int insertionsSize = insertions.size();
11080+
11081+
for (int i = 0; i < strings.size(); i++) {
11082+
BLangLiteral literal = strings.get(i);
11083+
String text = (String) literal.value;
11084+
String updatedText = text.replace("\\}", "}");
11085+
updatedText = updatedText.replace("`", ESCAPED_BACKTICK);
11086+
if (text.equals(updatedText)) {
11087+
updatedStrings.add(literal);
11088+
} else {
11089+
String[] split = updatedText.split(ESCAPED_BACKTICK);
11090+
11091+
int length = split.length;
11092+
for (int j = 0; j < length - 1; j++) {
11093+
String part = split[j];
11094+
updatedStrings.add(ASTBuilderUtil.createLiteral(pos, symTable.stringType, part));
11095+
updatedInsertions.add(ASTBuilderUtil.createLiteral(pos, symTable.stringType, "`"));
11096+
}
11097+
11098+
updatedStrings.add(ASTBuilderUtil.createLiteral(pos, symTable.stringType, split[length - 1]));
11099+
11100+
if (updatedText.endsWith(ESCAPED_BACKTICK)) {
11101+
updatedInsertions.add(ASTBuilderUtil.createLiteral(pos, symTable.stringType, "`"));
11102+
}
11103+
}
11104+
11105+
if (i < insertionsSize) {
11106+
updatedInsertions.add(insertions.get(i));
11107+
}
11108+
}
11109+
11110+
return ASTBuilderUtil.createRawTemplateExpression(
11111+
pos, symResolver.lookupPossibleMemberSymbol(
11112+
symTable.langNaturalModuleSymbol.scope,
11113+
Names.fromString("Prompt"),
11114+
SymTag.TYPE_DEF).type,
11115+
updatedStrings, updatedInsertions);
11116+
}
1101111117
}

compiler/ballerina-lang/src/main/java/org/wso2/ballerinalang/compiler/parser/BLangAnonymousModelHelper.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public class BLangAnonymousModelHelper {
4747
private final Map<PackageID, Integer> errorVarCount;
4848
private final Map<PackageID, Integer> intersectionRecordCount;
4949
private final Map<PackageID, Integer> intersectionErrorCount;
50+
private final Map<PackageID, Integer> naturalGeneratorCount;
5051
private final Map<PackageID, Map<String, Integer>> anonTypesNamesPerPkg;
5152

5253
public static final String ANON_PREFIX = "$anon";
@@ -63,6 +64,7 @@ public class BLangAnonymousModelHelper {
6364
private static final String TUPLE_VAR = "$tupleVar$";
6465
private static final String RECORD_VAR = "$recordVar$";
6566
private static final String ERROR_VAR = "$errorVar$";
67+
private static final String NATURAL_GENERATOR_VAR = "$naturalGeneratorVar$";
6668
private static final String DOLLAR = "$";
6769

6870
private static final CompilerContext.Key<BLangAnonymousModelHelper> ANONYMOUS_MODEL_HELPER_KEY =
@@ -81,6 +83,7 @@ private BLangAnonymousModelHelper(CompilerContext context) {
8183
intersectionRecordCount = new HashMap<>();
8284
intersectionErrorCount = new HashMap<>();
8385
distinctTypeIdCount = new HashMap<>();
86+
naturalGeneratorCount = new HashMap<>();
8487
anonTypesNamesPerPkg = new HashMap<>();
8588
}
8689

@@ -190,4 +193,10 @@ public String getNextAnonymousIntersectionErrorTypeName(PackageID packageID) {
190193
intersectionErrorCount.put(packageID, nextValue + 1);
191194
return ANON_INTERSECTION_ERROR_TYPE + UNDERSCORE + nextValue;
192195
}
196+
197+
public String getNextNaturalGeneratorVariableName(PackageID packageID) {
198+
Integer nextValue = naturalGeneratorCount.getOrDefault(packageID, 0);
199+
naturalGeneratorCount.put(packageID, nextValue + 1);
200+
return NATURAL_GENERATOR_VAR + UNDERSCORE + nextValue;
201+
}
193202
}

0 commit comments

Comments
 (0)