curl-programming-lang 1.4.0__tar.gz → 1.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (17) hide show
  1. {curl_programming_lang-1.4.0/curl_programming_lang.egg-info → curl_programming_lang-1.4.2}/PKG-INFO +67 -5
  2. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/README.md +66 -4
  3. curl_programming_lang-1.4.2/ai_module.py +291 -0
  4. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2/curl_programming_lang.egg-info}/PKG-INFO +67 -5
  5. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/interpreter.py +1 -1
  6. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/parser.py +24 -0
  7. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/pyproject.toml +1 -1
  8. curl_programming_lang-1.4.0/ai_module.py +0 -159
  9. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/LICENSE +0 -0
  10. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/curl_programming_lang.egg-info/SOURCES.txt +0 -0
  11. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/curl_programming_lang.egg-info/dependency_links.txt +0 -0
  12. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/curl_programming_lang.egg-info/entry_points.txt +0 -0
  13. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/curl_programming_lang.egg-info/top_level.txt +0 -0
  14. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/errors.py +0 -0
  15. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/lexer.py +0 -0
  16. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/main.py +0 -0
  17. {curl_programming_lang-1.4.0 → curl_programming_lang-1.4.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: curl-programming-lang
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: Curl is an open-source programming language built on Python technology
5
5
  Author: Ritvik Gautam
6
6
  License: Apache-2.0
@@ -47,9 +47,10 @@ git clone https://github.com/gautamritvik/Curl-Programming.git
47
47
  cd Curl-Programming
48
48
  pip install -e .
49
49
  ```
50
+
50
51
  ---
51
52
 
52
- ## Running the Curl terminal
53
+ ## Running the Curl terminal (REPL)
53
54
 
54
55
  ```
55
56
  curlang
@@ -61,6 +62,15 @@ curlang
61
62
  curlang [YOUR-FILE].curl
62
63
  ```
63
64
 
65
+ ## CLI flags
66
+
67
+ ```
68
+ curlang --version show version
69
+ curlang --license show license
70
+ curlang --credits show credits
71
+ curlang --help show help
72
+ ```
73
+
64
74
  ---
65
75
 
66
76
  ## Syntax Reference
@@ -81,7 +91,7 @@ pcType{"Hello, " + var{name} + "!"}\
81
91
  Prompts the user for input. The result is accessed anywhere with `input{ans}`.
82
92
 
83
93
  ```
84
- pcAsk{"What is your name?">>}\
94
+ pcAsk{"What is your name? >>"}\
85
95
  pcType{"You said: " + input{ans}}\
86
96
  ```
87
97
 
@@ -198,12 +208,51 @@ import{"math", m}\
198
208
 
199
209
  ### AI — `pcAI`
200
210
 
201
- *(Stubreserved for future AI integration.)*
211
+ `pcAI` is a **built-in AI module** no import required. It supports conversation history, system prompts, and an interactive chat mode.
212
+
213
+ Configure it with environment variables:
214
+
215
+ | Variable | Default | Description |
216
+ |---|---|---|
217
+ | `CURL_AI_KEY` or `OPENAI_API_KEY` | *(none)* | Your API key |
218
+ | `CURL_AI_BASE_URL` | `https://api.openai.com/v1` | API base URL |
219
+ | `CURL_AI_MODEL` | `gpt-4o-mini` | Model name |
220
+
221
+ Works with **OpenAI**, **OpenRouter**, **Ollama**, or any OpenAI-compatible API.
222
+
223
+ **Ask a question:**
224
+
225
+ ```
226
+ var{reply, pcAI.ask{"What is the capital of France?"}}\
227
+ pcType{var{reply}}\
228
+ ```
229
+
230
+ **Set a persona (system prompt):**
231
+
232
+ ```
233
+ pcAI.context{"You are a friendly pirate who answers in rhymes."}\
234
+ var{reply, pcAI.ask{"What is 2 + 2?"}}\
235
+ pcType{var{reply}}\
236
+ ```
237
+
238
+ **Interactive chat loop** (type `exit` to quit):
239
+
240
+ ```
241
+ pcAI.chat{""}\
242
+ ```
243
+
244
+ **Other methods:**
202
245
 
203
246
  ```
204
- pcAI{".on", "You are a helpful assistant", "profanityControl"}\
247
+ var{s, pcAI.summarize{"some long text"}}\
248
+ var{a, pcAI.analyze{"some data"}}\
249
+ var{mood, pcAI.sentiment{"I love this!"}}\
250
+ var{t, pcAI.translate{"Bonjour — translate to English"}}\
251
+ pcAI.reset{""}\
205
252
  ```
206
253
 
254
+ > Conversation history is kept across `pcAI.ask` calls and auto-compacts when it gets long.
255
+
207
256
  ---
208
257
 
209
258
  ## Symbols
@@ -221,6 +270,9 @@ pcAI{".on", "You are a helpful assistant", "profanityControl"}\
221
270
  | `!=` | Not equals |
222
271
  | `=` | Assignment |
223
272
  | `+` | Concatenation / addition |
273
+ | `-` | Subtraction |
274
+ | `*` | Multiplication |
275
+ | `/` | Division |
224
276
 
225
277
  ---
226
278
 
@@ -246,6 +298,16 @@ func{sayBye}\
246
298
 
247
299
  ---
248
300
 
301
+ ## Example AI program
302
+
303
+ ```
304
+ pcAI.context{"You are a helpful tutor."}\
305
+ var{answer, pcAI.ask{"Explain what a variable is in one sentence."}}\
306
+ pcType{var{answer}}\
307
+ ```
308
+
309
+ ---
310
+
249
311
  ## License
250
312
 
251
313
  This project is licensed under the Apache License 2.0 (OSI-approved).
@@ -28,9 +28,10 @@ git clone https://github.com/gautamritvik/Curl-Programming.git
28
28
  cd Curl-Programming
29
29
  pip install -e .
30
30
  ```
31
+
31
32
  ---
32
33
 
33
- ## Running the Curl terminal
34
+ ## Running the Curl terminal (REPL)
34
35
 
35
36
  ```
36
37
  curlang
@@ -42,6 +43,15 @@ curlang
42
43
  curlang [YOUR-FILE].curl
43
44
  ```
44
45
 
46
+ ## CLI flags
47
+
48
+ ```
49
+ curlang --version show version
50
+ curlang --license show license
51
+ curlang --credits show credits
52
+ curlang --help show help
53
+ ```
54
+
45
55
  ---
46
56
 
47
57
  ## Syntax Reference
@@ -62,7 +72,7 @@ pcType{"Hello, " + var{name} + "!"}\
62
72
  Prompts the user for input. The result is accessed anywhere with `input{ans}`.
63
73
 
64
74
  ```
65
- pcAsk{"What is your name?">>}\
75
+ pcAsk{"What is your name? >>"}\
66
76
  pcType{"You said: " + input{ans}}\
67
77
  ```
68
78
 
@@ -179,12 +189,51 @@ import{"math", m}\
179
189
 
180
190
  ### AI — `pcAI`
181
191
 
182
- *(Stubreserved for future AI integration.)*
192
+ `pcAI` is a **built-in AI module** no import required. It supports conversation history, system prompts, and an interactive chat mode.
193
+
194
+ Configure it with environment variables:
195
+
196
+ | Variable | Default | Description |
197
+ |---|---|---|
198
+ | `CURL_AI_KEY` or `OPENAI_API_KEY` | *(none)* | Your API key |
199
+ | `CURL_AI_BASE_URL` | `https://api.openai.com/v1` | API base URL |
200
+ | `CURL_AI_MODEL` | `gpt-4o-mini` | Model name |
201
+
202
+ Works with **OpenAI**, **OpenRouter**, **Ollama**, or any OpenAI-compatible API.
203
+
204
+ **Ask a question:**
205
+
206
+ ```
207
+ var{reply, pcAI.ask{"What is the capital of France?"}}\
208
+ pcType{var{reply}}\
209
+ ```
210
+
211
+ **Set a persona (system prompt):**
212
+
213
+ ```
214
+ pcAI.context{"You are a friendly pirate who answers in rhymes."}\
215
+ var{reply, pcAI.ask{"What is 2 + 2?"}}\
216
+ pcType{var{reply}}\
217
+ ```
218
+
219
+ **Interactive chat loop** (type `exit` to quit):
220
+
221
+ ```
222
+ pcAI.chat{""}\
223
+ ```
224
+
225
+ **Other methods:**
183
226
 
184
227
  ```
185
- pcAI{".on", "You are a helpful assistant", "profanityControl"}\
228
+ var{s, pcAI.summarize{"some long text"}}\
229
+ var{a, pcAI.analyze{"some data"}}\
230
+ var{mood, pcAI.sentiment{"I love this!"}}\
231
+ var{t, pcAI.translate{"Bonjour — translate to English"}}\
232
+ pcAI.reset{""}\
186
233
  ```
187
234
 
235
+ > Conversation history is kept across `pcAI.ask` calls and auto-compacts when it gets long.
236
+
188
237
  ---
189
238
 
190
239
  ## Symbols
@@ -202,6 +251,9 @@ pcAI{".on", "You are a helpful assistant", "profanityControl"}\
202
251
  | `!=` | Not equals |
203
252
  | `=` | Assignment |
204
253
  | `+` | Concatenation / addition |
254
+ | `-` | Subtraction |
255
+ | `*` | Multiplication |
256
+ | `/` | Division |
205
257
 
206
258
  ---
207
259
 
@@ -227,6 +279,16 @@ func{sayBye}\
227
279
 
228
280
  ---
229
281
 
282
+ ## Example AI program
283
+
284
+ ```
285
+ pcAI.context{"You are a helpful tutor."}\
286
+ var{answer, pcAI.ask{"Explain what a variable is in one sentence."}}\
287
+ pcType{var{answer}}\
288
+ ```
289
+
290
+ ---
291
+
230
292
  ## License
231
293
 
232
294
  This project is licensed under the Apache License 2.0 (OSI-approved).
@@ -0,0 +1,291 @@
1
+ import os
2
+ import re
3
+ import json
4
+ import urllib.request
5
+ import urllib.error
6
+
7
+ # ── ANSI terminal codes ───────────────────────────────────────────────────────
8
+ _R = "\033[0m" # reset
9
+ _B = "\033[1m" # bold
10
+ _I = "\033[3m" # italic
11
+ _U = "\033[4m" # underline
12
+ _CY = "\033[36m" # cyan (inline code)
13
+ _DM = "\033[2m" # dim (horizontal rules)
14
+
15
+ def _md(text):
16
+ """Convert basic Markdown to ANSI escape codes for terminal display."""
17
+ out = []
18
+ for line in text.split("\n"):
19
+ # headings
20
+ if line.startswith("### "):
21
+ line = f"{_B}{line[4:]}{_R}"
22
+ elif line.startswith("## "):
23
+ line = f"{_B}{_U}{line[3:]}{_R}"
24
+ elif line.startswith("# "):
25
+ line = f"{_B}{_U}{line[2:]}{_R}"
26
+ # horizontal rule
27
+ elif re.fullmatch(r'[-*_]{3,}', line.strip()):
28
+ line = f"{_DM}{'─' * 40}{_R}"
29
+ else:
30
+ # bullet points
31
+ line = re.sub(r'^(\s*)[-*] ', r'\1• ', line)
32
+ # bold + italic
33
+ line = re.sub(r'\*\*\*(.+?)\*\*\*', lambda m: f"{_B}{_I}{m.group(1)}{_R}", line)
34
+ # bold
35
+ line = re.sub(r'\*\*(.+?)\*\*', lambda m: f"{_B}{m.group(1)}{_R}", line)
36
+ # italic
37
+ line = re.sub(r'\*(.+?)\*', lambda m: f"{_I}{m.group(1)}{_R}", line)
38
+ # inline code
39
+ line = re.sub(r'`([^`]+)`', lambda m: f"{_CY}{m.group(1)}{_R}", line)
40
+ out.append(line)
41
+ return "\n".join(out)
42
+
43
+
44
+ # ── module constants ──────────────────────────────────────────────────────────
45
+ _DEFAULT_SYSTEM = """\
46
+ You are Curl-Bot, an AI assistant built into the Curl programming language.
47
+ Curl is an open-source programming language created by Ritvik Gautam that runs on Python.
48
+ You are helpful, concise, and friendly.
49
+ Respond in plain text only — no Markdown, no asterisks, no bullet symbols, no backticks.
50
+
51
+ === CURL LANGUAGE REFERENCE ===
52
+
53
+ Every statement ends with a backslash (\\).
54
+ Blocks open with - and close with --\\.
55
+
56
+ PRINT:
57
+ pcType{"Hello, world!"}\
58
+ pcType{"Hello " + var{name}}\
59
+
60
+ INPUT (stores in input{ans}):
61
+ pcAsk{"What is your name? >>"}\
62
+
63
+ VARIABLES:
64
+ var{name, "Ritvik"}\ — assign string
65
+ var{score, 100}\ — assign number
66
+ var{greeting, "Hi " + var{name}}\
67
+ pcType{var{name}}\ — print variable
68
+
69
+ LISTS:
70
+ list{1; 2; 3}\
71
+
72
+ FUNCTIONS:
73
+ createFunc{greet}-
74
+ pcType{"Hello!"}\
75
+ --\\
76
+ func{greet}\ — call the function
77
+
78
+ IF / ELIF / ELSE:
79
+ if{var{x} == 10, then}-
80
+ pcType{"ten"}\
81
+ --\\
82
+
83
+ if{var{x} == 10, then}-
84
+ pcType{"ten"}\
85
+ else:
86
+ pcType{"not ten"}\
87
+ --\\
88
+
89
+ if{var{x} > 10, then}-
90
+ pcType{"big"}\
91
+ elif{var{x} == 10, then}-
92
+ pcType{"exact"}\
93
+ --\\--\\
94
+
95
+ OPERATORS:
96
+ == equals != not equals
97
+ < less than > greater than
98
+ <= less/equal >= greater/equal
99
+ + concatenate or add
100
+ - subtract * multiply / divide
101
+ \\ end of line - open block --\\ close block
102
+ {} argument list "" string data ; list separator
103
+ , parameter sep
104
+
105
+ OTHER LANGUAGE BLOCKS:
106
+ otherCoding{"Python",
107
+ print("hi")
108
+ }\\
109
+
110
+ otherCoding{"JavaScript",
111
+ console.log("hi")
112
+ }\\
113
+
114
+ AI MODULE (built-in, no import needed):
115
+ pcAI.context{"You are a pirate."}\\ — set bot persona (resets history)
116
+ var{r, pcAI.ask{"What is 2+2?"}}\\ — ask a question (history kept)
117
+ pcType{var{r}}\\
118
+ pcAI.chat{""}\\ — start interactive chat loop (type exit to quit)
119
+ pcAI.reset{""}\\ — clear conversation history
120
+ pcAI.summarize{"some long text"}\\
121
+ pcAI.analyze{"some data"}\\
122
+ pcAI.sentiment{"I love this!"}\\ — returns: positive / negative / neutral
123
+ pcAI.translate{"Bonjour to English"}\\
124
+
125
+ IMPORTS:
126
+ import{"math", m}\\ — any Python stdlib or installed package
127
+
128
+ === END OF CURL REFERENCE ===
129
+ """
130
+
131
+ _COMPACT_THRESHOLD = 20 # auto-compact after this many messages in history
132
+
133
+
134
+ class CurlAIModule:
135
+ """
136
+ AI standard library for Curl.
137
+
138
+ Env vars:
139
+ CURL_AI_KEY / OPENAI_API_KEY — API key
140
+ CURL_AI_BASE_URL — base URL (default: https://api.openai.com/v1)
141
+ CURL_AI_MODEL — model (default: gpt-4o-mini)
142
+
143
+ Methods (Curl syntax):
144
+ ai.context{"system prompt"}\ — set bot persona
145
+ ai.ask{"prompt"}\ — one-shot question (history kept)
146
+ ai.chat{""}\ — interactive chat loop (exit to quit)
147
+ ai.reset{""}\ — clear history
148
+ ai.summarize{"text"}\
149
+ ai.analyze{"text"}\
150
+ ai.sentiment{"text"}\
151
+ ai.translate{"text to English"}\
152
+ """
153
+
154
+ def __init__(self):
155
+ self._system = _DEFAULT_SYSTEM
156
+ self._history = []
157
+
158
+ # ── configuration ─────────────────────────────────────────────────────────
159
+
160
+ def context(self, prompt):
161
+ """Set a persistent system prompt (persona) for all subsequent calls."""
162
+ self._system = str(prompt)
163
+ self._history = []
164
+ return ""
165
+
166
+ def reset(self, _=""):
167
+ """Clear conversation history while keeping the current context."""
168
+ self._history = []
169
+ return ""
170
+
171
+ # ── internal ──────────────────────────────────────────────────────────────
172
+
173
+ def _raw_request(self, messages):
174
+ api_key = os.environ.get("CURL_AI_KEY") or os.environ.get("OPENAI_API_KEY", "")
175
+ base_url = os.environ.get("CURL_AI_BASE_URL", "https://api.openai.com/v1").rstrip("/")
176
+ model = os.environ.get("CURL_AI_MODEL", "gpt-4o-mini")
177
+
178
+ if not api_key and "openai.com" in base_url:
179
+ raise RuntimeError(
180
+ "No API key found. Set CURL_AI_KEY (or OPENAI_API_KEY) in your environment.\n"
181
+ "For a free local model, install Ollama, run a model, then:\n"
182
+ " export CURL_AI_BASE_URL=http://localhost:11434/v1\n"
183
+ " export CURL_AI_MODEL=llama3.2"
184
+ )
185
+
186
+ payload = json.dumps({
187
+ "model": model,
188
+ "messages": messages,
189
+ "temperature": 0.7,
190
+ }).encode()
191
+
192
+ headers = {"Content-Type": "application/json"}
193
+ if api_key:
194
+ headers["Authorization"] = f"Bearer {api_key}"
195
+
196
+ req = urllib.request.Request(
197
+ f"{base_url}/chat/completions",
198
+ data=payload,
199
+ headers=headers,
200
+ )
201
+ try:
202
+ with urllib.request.urlopen(req, timeout=60) as resp:
203
+ result = json.loads(resp.read())
204
+ return result["choices"][0]["message"]["content"].strip()
205
+ except urllib.error.HTTPError as e:
206
+ body = e.read().decode(errors="ignore")
207
+ raise RuntimeError(f"AI request failed ({e.code}): {body}")
208
+ except urllib.error.URLError as e:
209
+ raise RuntimeError(f"AI connection failed: {e.reason}")
210
+
211
+ def _compact_history(self):
212
+ summary_messages = [
213
+ {"role": "system", "content": self._system},
214
+ {
215
+ "role": "user",
216
+ "content": (
217
+ "Summarize the following conversation in 3-5 bullet points "
218
+ "to use as context going forward. Be concise.\n\n"
219
+ + "\n".join(f"{m['role'].upper()}: {m['content']}" for m in self._history)
220
+ ),
221
+ },
222
+ ]
223
+ summary = self._raw_request(summary_messages)
224
+ self._history = [{"role": "assistant", "content": f"[Previous conversation summary]\n{summary}"}]
225
+
226
+ def _request(self, prompt):
227
+ if len(self._history) >= _COMPACT_THRESHOLD:
228
+ self._compact_history()
229
+ self._history.append({"role": "user", "content": str(prompt)})
230
+ messages = [{"role": "system", "content": self._system}] + self._history
231
+ reply = self._raw_request(messages)
232
+ self._history.append({"role": "assistant", "content": reply})
233
+ return reply
234
+
235
+ # ── public methods ────────────────────────────────────────────────────────
236
+
237
+ def ask(self, prompt):
238
+ """Send a prompt (history kept) and return the response."""
239
+ return _md(self._request(prompt))
240
+
241
+ def chat(self, _=""):
242
+ """Start an interactive chat loop. Type 'exit' to quit."""
243
+ print(f"\n{_B}Curl-Bot Chat{_R} — type {_CY}exit{_R} to quit\n")
244
+ while True:
245
+ try:
246
+ user_input = input(f"{_B}You:{_R} ").strip()
247
+ except (EOFError, KeyboardInterrupt):
248
+ print("\nGoodbye!")
249
+ break
250
+ if user_input.lower() == "exit":
251
+ print("Goodbye!")
252
+ break
253
+ if not user_input:
254
+ continue
255
+ reply = self._request(user_input)
256
+ print(f"\n{_B}Curl-Bot:{_R} {_md(reply)}\n")
257
+ return ""
258
+
259
+ def summarize(self, text):
260
+ messages = [
261
+ {"role": "system", "content": self._system},
262
+ {"role": "user", "content": f"Summarize in 2-3 sentences:\n\n{text}"},
263
+ ]
264
+ return _md(self._raw_request(messages))
265
+
266
+ def analyze(self, text):
267
+ messages = [
268
+ {"role": "system", "content": self._system},
269
+ {"role": "user", "content": f"Analyze and provide key insights:\n\n{text}"},
270
+ ]
271
+ return _md(self._raw_request(messages))
272
+
273
+ def sentiment(self, text):
274
+ messages = [
275
+ {"role": "system", "content": self._system},
276
+ {
277
+ "role": "user",
278
+ "content": (
279
+ "What is the sentiment? Reply with ONE word only: positive, negative, or neutral.\n\n"
280
+ + text
281
+ ),
282
+ },
283
+ ]
284
+ return self._raw_request(messages) # raw — used in comparisons
285
+
286
+ def translate(self, text):
287
+ messages = [
288
+ {"role": "system", "content": self._system},
289
+ {"role": "user", "content": f"Translate the following:\n\n{text}"},
290
+ ]
291
+ return _md(self._raw_request(messages))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: curl-programming-lang
3
- Version: 1.4.0
3
+ Version: 1.4.2
4
4
  Summary: Curl is an open-source programming language built on Python technology
5
5
  Author: Ritvik Gautam
6
6
  License: Apache-2.0
@@ -47,9 +47,10 @@ git clone https://github.com/gautamritvik/Curl-Programming.git
47
47
  cd Curl-Programming
48
48
  pip install -e .
49
49
  ```
50
+
50
51
  ---
51
52
 
52
- ## Running the Curl terminal
53
+ ## Running the Curl terminal (REPL)
53
54
 
54
55
  ```
55
56
  curlang
@@ -61,6 +62,15 @@ curlang
61
62
  curlang [YOUR-FILE].curl
62
63
  ```
63
64
 
65
+ ## CLI flags
66
+
67
+ ```
68
+ curlang --version show version
69
+ curlang --license show license
70
+ curlang --credits show credits
71
+ curlang --help show help
72
+ ```
73
+
64
74
  ---
65
75
 
66
76
  ## Syntax Reference
@@ -81,7 +91,7 @@ pcType{"Hello, " + var{name} + "!"}\
81
91
  Prompts the user for input. The result is accessed anywhere with `input{ans}`.
82
92
 
83
93
  ```
84
- pcAsk{"What is your name?">>}\
94
+ pcAsk{"What is your name? >>"}\
85
95
  pcType{"You said: " + input{ans}}\
86
96
  ```
87
97
 
@@ -198,12 +208,51 @@ import{"math", m}\
198
208
 
199
209
  ### AI — `pcAI`
200
210
 
201
- *(Stubreserved for future AI integration.)*
211
+ `pcAI` is a **built-in AI module** no import required. It supports conversation history, system prompts, and an interactive chat mode.
212
+
213
+ Configure it with environment variables:
214
+
215
+ | Variable | Default | Description |
216
+ |---|---|---|
217
+ | `CURL_AI_KEY` or `OPENAI_API_KEY` | *(none)* | Your API key |
218
+ | `CURL_AI_BASE_URL` | `https://api.openai.com/v1` | API base URL |
219
+ | `CURL_AI_MODEL` | `gpt-4o-mini` | Model name |
220
+
221
+ Works with **OpenAI**, **OpenRouter**, **Ollama**, or any OpenAI-compatible API.
222
+
223
+ **Ask a question:**
224
+
225
+ ```
226
+ var{reply, pcAI.ask{"What is the capital of France?"}}\
227
+ pcType{var{reply}}\
228
+ ```
229
+
230
+ **Set a persona (system prompt):**
231
+
232
+ ```
233
+ pcAI.context{"You are a friendly pirate who answers in rhymes."}\
234
+ var{reply, pcAI.ask{"What is 2 + 2?"}}\
235
+ pcType{var{reply}}\
236
+ ```
237
+
238
+ **Interactive chat loop** (type `exit` to quit):
239
+
240
+ ```
241
+ pcAI.chat{""}\
242
+ ```
243
+
244
+ **Other methods:**
202
245
 
203
246
  ```
204
- pcAI{".on", "You are a helpful assistant", "profanityControl"}\
247
+ var{s, pcAI.summarize{"some long text"}}\
248
+ var{a, pcAI.analyze{"some data"}}\
249
+ var{mood, pcAI.sentiment{"I love this!"}}\
250
+ var{t, pcAI.translate{"Bonjour — translate to English"}}\
251
+ pcAI.reset{""}\
205
252
  ```
206
253
 
254
+ > Conversation history is kept across `pcAI.ask` calls and auto-compacts when it gets long.
255
+
207
256
  ---
208
257
 
209
258
  ## Symbols
@@ -221,6 +270,9 @@ pcAI{".on", "You are a helpful assistant", "profanityControl"}\
221
270
  | `!=` | Not equals |
222
271
  | `=` | Assignment |
223
272
  | `+` | Concatenation / addition |
273
+ | `-` | Subtraction |
274
+ | `*` | Multiplication |
275
+ | `/` | Division |
224
276
 
225
277
  ---
226
278
 
@@ -246,6 +298,16 @@ func{sayBye}\
246
298
 
247
299
  ---
248
300
 
301
+ ## Example AI program
302
+
303
+ ```
304
+ pcAI.context{"You are a helpful tutor."}\
305
+ var{answer, pcAI.ask{"Explain what a variable is in one sentence."}}\
306
+ pcType{var{answer}}\
307
+ ```
308
+
309
+ ---
310
+
249
311
  ## License
250
312
 
251
313
  This project is licensed under the Apache License 2.0 (OSI-approved).
@@ -7,7 +7,7 @@ def execute(ast, env=None):
7
7
  env = {
8
8
  "variables": {},
9
9
  "functions": {},
10
- "imports": {},
10
+ "imports": {"pcAI": CurlAIModule()}, # built-in, no import needed
11
11
  "last_input": None,
12
12
  }
13
13
  for stmt in ast:
@@ -82,6 +82,10 @@ class Parser:
82
82
  if token[0] == IDENTIFIER and self.peek() and self.peek()[0] == DOT:
83
83
  return self.parse_method_call_stmt()
84
84
 
85
+ # pcAI.method{arg}\ — built-in AI module, no import needed
86
+ if token[0] == KEYWORD and token[1] == "pcAI" and self.peek() and self.peek()[0] == DOT:
87
+ return self.parse_pcai_method_call_stmt()
88
+
85
89
  if token[0] != KEYWORD:
86
90
  raise SyntaxError(f"Expected a Curl keyword, got {token[0]} {repr(token[1])}")
87
91
 
@@ -217,6 +221,16 @@ class Parser:
217
221
  self.consume(LINE_END)
218
222
  return {"type": "method_call", "module": module, "method": method, "arg": arg}
219
223
 
224
+ def parse_pcai_method_call_stmt(self):
225
+ self.consume(KEYWORD, "pcAI")
226
+ self.consume(DOT)
227
+ method = self.consume(IDENTIFIER)[1]
228
+ self.consume(LBRACE)
229
+ arg = self.parse_concat_expr()
230
+ self.consume(RBRACE)
231
+ self.consume(LINE_END)
232
+ return {"type": "method_call", "module": "pcAI", "method": method, "arg": arg}
233
+
220
234
  def parse_import(self):
221
235
  self.consume(KEYWORD, "import")
222
236
  self.consume(LBRACE)
@@ -281,6 +295,16 @@ class Parser:
281
295
  if token[0] == KEYWORD:
282
296
  kw = token[1]
283
297
 
298
+ # pcAI.method{arg} as an expression — e.g. var{x, pcAI.ask{"prompt"}}\
299
+ if kw == "pcAI" and self.peek() and self.peek()[0] == DOT:
300
+ self.pos += 1 # consume pcAI
301
+ self.consume(DOT)
302
+ method = self.consume(IDENTIFIER)[1]
303
+ self.consume(LBRACE)
304
+ arg = self.parse_concat_expr()
305
+ self.consume(RBRACE)
306
+ return {"type": "method_call", "module": "pcAI", "method": method, "arg": arg}
307
+
284
308
  if kw == "var":
285
309
  self.pos += 1
286
310
  self.consume(LBRACE)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "curl-programming-lang"
7
- version = "1.4.0"
7
+ version = "1.4.2"
8
8
  description = "Curl is an open-source programming language built on Python technology"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.7"
@@ -1,159 +0,0 @@
1
- import os
2
- import json
3
- import urllib.request
4
- import urllib.error
5
-
6
- _DEFAULT_SYSTEM = (
7
- "You are Curl-Bot, an AI assistant built into the Curl programming language. "
8
- "Curl is an open-source language created by Ritvik Gautam that runs on Python. "
9
- "You are helpful, concise, and friendly."
10
- )
11
-
12
- # Auto-compact after this many user+assistant message pairs in history
13
- _COMPACT_THRESHOLD = 20
14
-
15
-
16
- class CurlAIModule:
17
- """
18
- AI standard library for Curl.
19
-
20
- Configuration via environment variables:
21
- CURL_AI_KEY or OPENAI_API_KEY — API key (not needed for local models)
22
- CURL_AI_BASE_URL — base URL (default: https://api.openai.com/v1)
23
- set to http://localhost:11434/v1 for Ollama
24
- CURL_AI_MODEL — model name (default: gpt-4o-mini)
25
-
26
- Usage in Curl:
27
- import{"ai", ai}\
28
- ai.context{"You are a pirate who only speaks in rhymes."}\
29
- var{answer, ai.ask{"What is the capital of France?"}}\
30
- pcType{var{answer}}\
31
- """
32
-
33
- def __init__(self):
34
- self._system = _DEFAULT_SYSTEM
35
- self._history = [] # list of {"role": ..., "content": ...}
36
-
37
- def context(self, prompt):
38
- """Set a persistent system prompt (persona/context) for all subsequent AI calls."""
39
- self._system = str(prompt)
40
- self._history = [] # reset history when context changes
41
- return ""
42
-
43
- def reset(self, _=""):
44
- """Clear conversation history (start a fresh chat while keeping context)."""
45
- self._history = []
46
- return ""
47
-
48
- def _raw_request(self, messages):
49
- """Send a messages list to the API and return the reply string."""
50
- api_key = os.environ.get("CURL_AI_KEY") or os.environ.get("OPENAI_API_KEY", "")
51
- base_url = os.environ.get("CURL_AI_BASE_URL", "https://api.openai.com/v1").rstrip("/")
52
- model = os.environ.get("CURL_AI_MODEL", "gpt-4o-mini")
53
-
54
- if not api_key and "openai.com" in base_url:
55
- raise RuntimeError(
56
- "No API key found. Set CURL_AI_KEY (or OPENAI_API_KEY) in your environment.\n"
57
- "For a free local model, install Ollama (https://ollama.com), run a model, then set:\n"
58
- " export CURL_AI_BASE_URL=http://localhost:11434/v1\n"
59
- " export CURL_AI_MODEL=llama3.2"
60
- )
61
-
62
- payload = json.dumps({
63
- "model": model,
64
- "messages": messages,
65
- "temperature": 0.7,
66
- }).encode()
67
-
68
- headers = {"Content-Type": "application/json"}
69
- if api_key:
70
- headers["Authorization"] = f"Bearer {api_key}"
71
-
72
- req = urllib.request.Request(
73
- f"{base_url}/chat/completions",
74
- data=payload,
75
- headers=headers,
76
- )
77
-
78
- try:
79
- with urllib.request.urlopen(req, timeout=60) as resp:
80
- result = json.loads(resp.read())
81
- return result["choices"][0]["message"]["content"].strip()
82
- except urllib.error.HTTPError as e:
83
- body = e.read().decode(errors="ignore")
84
- raise RuntimeError(f"AI request failed ({e.code}): {body}")
85
- except urllib.error.URLError as e:
86
- raise RuntimeError(f"AI connection failed: {e.reason}")
87
-
88
- def _compact_history(self):
89
- """Summarize old history into a single assistant message to stay within limits."""
90
- summary_messages = [
91
- {"role": "system", "content": self._system},
92
- {
93
- "role": "user",
94
- "content": (
95
- "Summarize the following conversation history into 3-5 bullet points "
96
- "so it can be used as context going forward. Be concise.\n\n"
97
- + "\n".join(
98
- f"{m['role'].upper()}: {m['content']}" for m in self._history
99
- )
100
- ),
101
- },
102
- ]
103
- summary = self._raw_request(summary_messages)
104
- self._history = [{"role": "assistant", "content": f"[Previous conversation summary]\n{summary}"}]
105
-
106
- def _request(self, prompt):
107
- """Send prompt with history, auto-compact when history is too long."""
108
- if len(self._history) >= _COMPACT_THRESHOLD:
109
- self._compact_history()
110
-
111
- self._history.append({"role": "user", "content": str(prompt)})
112
-
113
- messages = [{"role": "system", "content": self._system}] + self._history
114
- reply = self._raw_request(messages)
115
-
116
- self._history.append({"role": "assistant", "content": reply})
117
- return reply
118
-
119
- def ask(self, prompt):
120
- """Send a prompt (with conversation history) and return the response."""
121
- return self._request(prompt)
122
-
123
- def summarize(self, text):
124
- """Summarize text in 2-3 sentences (no history tracking)."""
125
- messages = [
126
- {"role": "system", "content": self._system},
127
- {"role": "user", "content": f"Summarize the following in 2-3 sentences:\n\n{text}"},
128
- ]
129
- return self._raw_request(messages)
130
-
131
- def analyze(self, text):
132
- """Analyze text and return key insights (no history tracking)."""
133
- messages = [
134
- {"role": "system", "content": self._system},
135
- {"role": "user", "content": f"Analyze the following and provide key insights:\n\n{text}"},
136
- ]
137
- return self._raw_request(messages)
138
-
139
- def sentiment(self, text):
140
- """Return the sentiment of text: positive, negative, or neutral (no history tracking)."""
141
- messages = [
142
- {"role": "system", "content": self._system},
143
- {
144
- "role": "user",
145
- "content": (
146
- "What is the sentiment of this text? "
147
- "Reply with only one word: positive, negative, or neutral.\n\n" + text
148
- ),
149
- },
150
- ]
151
- return self._raw_request(messages)
152
-
153
- def translate(self, text):
154
- """Translate text — include the target language in the text itself (no history tracking)."""
155
- messages = [
156
- {"role": "system", "content": self._system},
157
- {"role": "user", "content": f"Translate the following:\n\n{text}"},
158
- ]
159
- return self._raw_request(messages)